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

PEP-518 support: configure bandit via pyproject.toml #401

Merged
merged 27 commits into from Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4a40e04
parse config from toml
orsinium Oct 8, 2018
98ff64b
test toml config parsing
orsinium Oct 8, 2018
d49c487
update docs
orsinium Oct 8, 2018
6154e9e
FIX pep8 "line too long" in tests
orsinium Oct 8, 2018
bfb4cba
review
orsinium Oct 9, 2018
6578950
Merge remote-tracking branch 'PyCQA/master' into toml
orsinium Mar 4, 2019
bdf6c18
+extras
orsinium Mar 4, 2019
fac79ba
use setup.cfg for extras
orsinium Mar 5, 2019
7bcce45
Merge branch 'master' into toml
orsinium Oct 16, 2019
15f31e2
Merge branch 'master' into toml
orsinium Nov 4, 2019
be67498
Merge branch 'master' into toml
ericwb Jan 12, 2020
9f982b1
Merge branch 'master' into toml
ericwb Jan 21, 2020
bd4b927
Merge branch 'master' into toml
lukehinds Mar 7, 2020
c6d7e38
fix setup.cfg
orsinium Mar 9, 2020
0b6e636
fix
orsinium Mar 9, 2020
67d00c9
Merge branch 'master' into toml
orsinium Mar 30, 2020
e128337
Merge branch 'master' into toml
orsinium May 8, 2020
ddb063e
Merge branch 'master' into toml
orsinium Jun 15, 2020
e966372
Merge branch 'master' into toml
orsinium Jan 5, 2021
027a8cb
Merge branch 'master' into toml
lukehinds Feb 12, 2021
41c8ba6
Apply suggestions from code review
orsinium Feb 16, 2021
edef1b0
Update doc/source/config.rst
orsinium Feb 16, 2021
f09f47b
Merge branch 'master' into toml
ericwb May 13, 2021
48b713c
Merge branch 'master' into toml
ericwb Aug 13, 2021
3e04a66
Update doc/source/config.rst
orsinium Aug 14, 2021
6600e52
actualize TOML config example in docs
orsinium Aug 18, 2021
d8fce0d
Merge branch 'master' into toml
ericwb Aug 24, 2021
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
24 changes: 17 additions & 7 deletions bandit/core/config.py
Expand Up @@ -36,13 +36,23 @@ def __init__(self, config_file=None):
raise utils.ConfigError("Could not read config file.",
config_file)

try:
with f:
self._config = yaml.safe_load(f)
self.validate(config_file)
except yaml.YAMLError as err:
LOG.error(err)
raise utils.ConfigError("Error parsing file.", config_file)
if config_file.endswith('.toml'):
import toml
try:
with f:
self._config = toml.load(f)['tool']['bandit']
except toml.TomlDecodeError as err:
LOG.error(err)
raise utils.ConfigError("Error parsing file.", config_file)
else:
try:
with f:
self._config = yaml.safe_load(f)
except yaml.YAMLError as err:
LOG.error(err)
raise utils.ConfigError("Error parsing file.", config_file)

self.validate(config_file)

# valid config must be a dict
if not isinstance(self._config, dict):
Expand Down
53 changes: 53 additions & 0 deletions doc/source/config.rst
Expand Up @@ -37,6 +37,59 @@ several config files and pick from them using `-c`. If you only wish to control
the specific tests that are to be run (and not their parameters) then using
`-s` or `-t` on the command line may be more appropriate.

Also you can configure bandit via
`pyproject.toml <https://www.python.org/dev/peps/pep-0518/>`_ file. In this
case you would explicitly specify the path to configuration via `-c` too.
For example:

.. code-block:: TOML

[tool.bandit]
tests = ["B201", "B301"]
skips = ["B101", "B601"]

[tool.bandit.any_other_function_with_shell_equals_true]
no_shell = [
"os.execl",
"os.execle",
"os.execlp",
"os.execlpe",
"os.execv",
"os.execve",
"os.execvp",
"os.execvpe",
"os.spawnl",
"os.spawnle",
"os.spawnlp",
"os.spawnlpe",
"os.spawnv",
"os.spawnve",
"os.spawnvp",
"os.spawnvpe",
"os.startfile"
]
shell = [
"os.system",
"os.popen",
"os.popen2",
"os.popen3",
"os.popen4",
"popen2.popen2",
"popen2.popen3",
"popen2.popen4",
"popen2.Popen3",
"popen2.Popen4",
"commands.getoutput",
"commands.getstatusoutput"
]
subprocess = [
"subprocess.Popen",
"subprocess.call",
"subprocess.check_call",
"subprocess.check_output"
]


Skipping Tests
--------------
The bandit config may contain optional lists of test IDs to either include
Expand Down
8 changes: 7 additions & 1 deletion setup.cfg
Expand Up @@ -27,7 +27,13 @@ classifier =
project_urls =
Release notes = https://github.com/PyCQA/bandit/releases

[entry_points]
[options.extras_require]
yaml =
PyYAML
toml =
toml

[options.entry_points]
console_scripts =
bandit = bandit.cli.main:main
bandit-config-generator = bandit.cli.config_generator:main
Expand Down
1 change: 1 addition & 0 deletions test-requirements.txt
Expand Up @@ -7,5 +7,6 @@ hacking>=2.0.0 # Apache-2.0
stestr>=2.5.0 # Apache-2.0
testscenarios>=0.5.0 # Apache-2.0/BSD
testtools>=2.3.0 # MIT
toml # MIT
beautifulsoup4>=4.8.0 # MIT
pylint==1.9.4 # GPLv2
49 changes: 45 additions & 4 deletions tests/unit/core/test_config.py
Expand Up @@ -16,14 +16,16 @@


class TempFile(fixtures.Fixture):
def __init__(self, contents=None):
def __init__(self, contents=None, suffix='.yaml'):
super(TempFile, self).__init__()
self.contents = contents
self.suffix = suffix

def setUp(self):
super(TempFile, self).setUp()

with tempfile.NamedTemporaryFile(mode='wt', delete=False) as f:
with tempfile.NamedTemporaryFile(suffix=self.suffix, mode='wt',
delete=False) as f:
if self.contents:
f.write(self.contents)

Expand Down Expand Up @@ -112,7 +114,7 @@ def test_not_exist(self):


class TestConfigCompat(testtools.TestCase):
sample_yaml = textwrap.dedent("""
sample = textwrap.dedent("""
profiles:
test_1:
include:
Expand Down Expand Up @@ -157,10 +159,11 @@ class TestConfigCompat(testtools.TestCase):
level: HIGH
message: "{module} is considered insecure."
""")
suffix = '.yaml'

def setUp(self):
super(TestConfigCompat, self).setUp()
f = self.useFixture(TempFile(self.sample_yaml))
f = self.useFixture(TempFile(self.sample, suffix=self.suffix))
self.config = config.BanditConfig(f.name)

def test_converted_include(self):
Expand Down Expand Up @@ -252,3 +255,41 @@ def test_bad_yaml(self):
self.config = config.BanditConfig(f.name)
except utils.ConfigError as e:
self.assertIn("Error parsing file.", e.message)


class TestTomlConfig(TestConfigCompat):
sample = textwrap.dedent("""
Copy link
Member

Choose a reason for hiding this comment

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

This block would be good as a fixture.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This isn't fixture. I want to run same test cases twice for two different configs. Fixture, contrariwise, allows you to reuse same set ups in different test cases. Inheritance works perfect in this case.

[tool.bandit.profiles.test_1]
include = [
"any_other_function_with_shell_equals_true",
"assert_used",
]

[tool.bandit.profiles.test_2]
include = ["blacklist_calls"]

[tool.bandit.profiles.test_3]
include = ["blacklist_imports"]

[tool.bandit.profiles.test_4]
exclude = ["assert_used"]

[tool.bandit.profiles.test_5]
exclude = ["blacklist_calls", "blacklist_imports"]

[tool.bandit.profiles.test_6]
include = ["blacklist_calls"]
exclude = ["blacklist_imports"]

[[tool.bandit.blacklist_calls.bad_name_sets]]
[tool.bandit.blacklist_calls.bad_name_sets.pickle]
qualnames = ["pickle.loads"]
message = "{func} library appears to be in use."

[[tool.bandit.blacklist_imports.bad_import_sets]]
[tool.bandit.blacklist_imports.bad_import_sets.telnet]
imports = ["telnetlib"]
level = "HIGH"
message = "{module} is considered insecure."
""")
suffix = '.toml'