Repository: PyCQA/bandit
Pull request #510 (2019-07-02 16:30:13)

--exit-zero option

frankyjquintero: This feature is necessary for a CI environment where only the report is required for SonarQube or any other tool.

The --exit-zero parameter will prevent a pipeline from brokering and generating the report
maciejstromich: @ericwb I've added the missing docs to man page source.
frankyjquintero: @ericwb the requested changes @maciejstromich has finished them. Is this feature available in the next version as soon as possible? : D it would be great to be able to implement it as soon as possible.
maciejstromich: @frankyjquintero for the time being you can just add
```
git+https://github.com/maciejstromich/bandit.git@exit_zero
```
to your requirements.txt (that's the branch from which this PR is being made)

Patch:
diff --git a/README.rst b/README.rst
index 9886620..0530b86 100644
--- a/README.rst
+++ b/README.rst
@@ -99,7 +99,7 @@ Usage::
                   [-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] [--version]
+                  [--ini INI_PATH] [--exit-zero] [--version]
                   [targets [targets ...]]
 
     Bandit - a Python source code security analyzer
@@ -151,6 +151,7 @@ Usage::
                             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
diff --git a/bandit/cli/main.py b/bandit/cli/main.py
index 1e74682..6c0cfeb 100644
--- a/bandit/cli/main.py
+++ b/bandit/cli/main.py
@@ -20,14 +20,12 @@ import os
 import sys
 import textwrap
 
-
 import bandit
 from bandit.core import config as b_config
 from bandit.core import constants
 from bandit.core import manager as b_manager
 from bandit.core import utils
 
-
 BASE_CONFIG = 'bandit.yaml'
 LOG = logging.getLogger()
 
@@ -249,6 +247,9 @@ def main():
         '--ini', dest='ini_path', action='store', default=None,
         help='path to a .bandit file that supplies command line arguments'
     )
+    parser.add_argument('--exit-zero', action='store_true', dest='exit_zero',
+                        default=False, help='exit with 0, '
+                                            'even with results found')
     python_ver = sys.version.replace('\n', '')
     parser.add_argument(
         '--version', action='version',
@@ -403,7 +404,8 @@ def main():
                          args.msg_template)
 
     # return an exit code of 1 if there are results, 0 otherwise
-    if b_mgr.results_count(sev_filter=sev_level, conf_filter=conf_level) > 0:
+    if (b_mgr.results_count(sev_filter=sev_level, conf_filter=conf_level) > 0
+            and not args.exit_zero):
         sys.exit(1)
     else:
         sys.exit(0)
diff --git a/doc/source/man/bandit.rst b/doc/source/man/bandit.rst
index 0fecb1e..971e947 100644
--- a/doc/source/man/bandit.rst
+++ b/doc/source/man/bandit.rst
@@ -10,7 +10,7 @@ bandit [-h] [-r] [-a {file,vuln}] [-n CONTEXT_LINES] [-c CONFIG_FILE]
             [-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] [--version]
+            [--ini INI_PATH] [--exit-zero] [--version]
             targets [targets ...]
 
 DESCRIPTION
@@ -67,6 +67,7 @@ OPTIONS
                         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


Test patch:
diff --git a/tests/unit/cli/test_main.py b/tests/unit/cli/test_main.py
index 30fa493..e1a81f7 100644
--- a/tests/unit/cli/test_main.py
+++ b/tests/unit/cli/test_main.py
@@ -287,3 +287,17 @@ class BanditCLIMainTests(testtools.TestCase):
             mock_mgr_results_ct.return_value = 0
             # assert a SystemExit with code 0
             self.assertRaisesRegex(SystemExit, '0', bandit.main)
+
+    @mock.patch('sys.argv', ['bandit', '-c', 'bandit.yaml', 'test', '-o',
+                             'output', '--exit-zero'])
+    def test_main_exit_with_results_and_with_exit_zero_flag(self):
+        # Test that bandit exits when there are results
+        temp_directory = self.useFixture(fixtures.TempDir()).path
+        os.chdir(temp_directory)
+        with open('bandit.yaml', 'wt') as fd:
+            fd.write(bandit_config_content)
+        with mock.patch('bandit.core.manager.BanditManager.results_count'
+                        ) as mock_mgr_results_ct:
+            mock_mgr_results_ct.return_value = 1
+            # assert a SystemExit with code 1
+            self.assertRaisesRegex(SystemExit, '0', bandit.main)