PyCQA / bandit

Bandit is a tool designed to find common security issues in Python code.
https://bandit.readthedocs.io
Apache License 2.0
6.42k stars 603 forks source link

Add an auto-fix or auto-correct feature #439

Open ericwb opened 5 years ago

ericwb commented 5 years ago

Is your feature request related to a problem? Please describe. It's nice that Bandit flags lines of code that require attention, but it would be even more valuable to suggest fixes for problem lines. Other linters such as ESLint provide a --fix command line option to automatically fix problems it finds.

See https://eslint.org/docs/user-guide/command-line-interface#options

Describe the solution you'd like A start might be that Bandit includes another field in the output data called suggested fix or something. It would include the modified line of code it found to be wrong with the proposed solution.

For example, if the yaml_load plugin found a case of yaml.load(), it would replace with yaml.load(Loader=yaml.SafeLoader).

Each plugin would need to handle fixes it could address.

Describe alternatives you've considered n/a

Additional context https://developer.ibm.com/articles/auto-fix-and-format-your-javascript-with-eslint/

lukehinds commented 5 years ago

Nice idea. Would it give a generic example, or try to amend and suggest the flagged line of code from the project being scanned?

ericwb commented 5 years ago

@lukehinds Yeah, I was thinking Bandit would output a new field of the suggested fix. But it could also have a command line option to actually make the changes in the file automatically. Similar to what ESLint offers.

ehooo commented 5 years ago

I think this is a great idea. Maybe could be added on the Issue class a new optional field.

ericwb commented 2 years ago

I investigated this some. The ast includes a NodeTransformer that enables rewriting the tree. And in Python 3.9 and later, ast can do an unparse in addition to parse. So in effect, you can create a suggested fix and even automatically fix the code.

However, Python's ast is not a CST (comcrete syntax tree) and therefore doesn't include things like trailing comments. The undesirable effect is that suggested code wouldn't retain these elements.

We could look at switching Bandit to use something like libcst. But this would be a major change to the base parsing mechanism of Bandit and adds another dependency.

ericwb commented 2 years ago

Here's a short example using libcst to auto-correct a problem in code, all while preserving the comments.

import libcst as cst

code = '''
from paramiko import client

class foo:
    def test(self):
        if True:
            ssh_client = client.SSHClient()
            # test test test
            ssh_client.set_missing_host_key_policy(client.AutoAddPolicy) # comment test
'''

class PolicyFix(cst.CSTTransformer):
    def leave_Call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.Call:
        if (cst.ensure_type(original_node.func, cst.Attribute)
            and original_node.func.attr.value == "set_missing_host_key_policy"
            and original_node.args[0].value.attr.value == "AutoAddPolicy"
        ):
            return updated_node.with_deep_changes(
                old_node=updated_node.args[0].value,
                attr=cst.Name("RejectPolicy")
            )
        else:
            return original_node

tree = cst.parse_module(code)
new_tree = tree.visit(PolicyFix())
print(new_tree.code)