From 14b3858005c52ccae64953b2920beefd0514a2e4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 28 Nov 2022 22:42:23 +0100 Subject: [PATCH] Adding exit codes (#76) * Adding exit codes * Limits the exit code to 1 if it's >=1 * Added patch from @christophetd adding --exit-non-zero-on-finding --- guarddog/cli.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/guarddog/cli.py b/guarddog/cli.py index edd82d79..cc4530e4 100644 --- a/guarddog/cli.py +++ b/guarddog/cli.py @@ -16,7 +16,7 @@ analyzer = Analyzer() ALL_RULES = analyzer.sourcecode_ruleset | analyzer.metadata_ruleset - +EXIT_CODE_ISSUES_FOUND = 1 @click.group def cli(): @@ -27,7 +27,8 @@ def cli(): @cli.command("verify") @click.argument("path") @click.option("--json", default=False, is_flag=True, help="Dump the output as JSON to standard out") -def verify(path, json): +@click.option("--exit-non-zero-on-finding", default=False, is_flag=True, help="Exit with a non-zero status code if at least one issue is identified") +def verify(path, json, exit_non_zero_on_finding): """Verify a requirements.txt file Args: @@ -44,6 +45,8 @@ def verify(path, json): import json as js print(js.dumps(results)) + if exit_non_zero_on_finding: + exit_with_status_code(results) @cli.command("scan") @click.argument("identifier") @@ -51,7 +54,8 @@ def verify(path, json): @click.option("-r", "--rules", multiple=True, type=click.Choice(ALL_RULES, case_sensitive=False)) @click.option("-x", "--exclude-rules", multiple=True, type=click.Choice(ALL_RULES, case_sensitive=False)) @click.option("--json", default=False, is_flag=True, help="Dump the output as JSON to standard out") -def scan(identifier, version, rules, exclude_rules, json): +@click.option("--exit-non-zero-on-finding", default=False, is_flag=True, help="Exit with a non-zero status code if at least one issue is identified") +def scan(identifier, version, rules, exclude_rules, json, exit_non_zero_on_finding): """Scan a package Args: @@ -84,6 +88,9 @@ def scan(identifier, version, rules, exclude_rules, json): else: print_scan_results(results, identifier) + if exit_non_zero_on_finding: + exit_with_status_code(results) + # Determines if the input passed to the 'scan' command is a local package name def is_local_package(input): identifier_is_path = re.search(r"(.{0,2}\/)+.+", input) @@ -93,6 +100,7 @@ def is_local_package(input): # Pretty prints scan results for the console def print_scan_results(results, identifier): num_issues = results.get('issues') + if num_issues == 0: print("Found " + colored('0 potentially malicious indicators', 'green', attrs=['bold']) + " scanning " + colored(identifier, None, attrs=['bold'])) print() @@ -113,5 +121,14 @@ def print_scan_results(results, identifier): for finding in source_code_findings: print(' * ' + finding['message'] + ' at ' + finding['location'] + '\n ' + format_code_line_for_output(finding['code'])) print() + + def format_code_line_for_output(code): - return ' ' + colored(code.strip().replace('\n', '\n ').replace('\t', ' '), None, 'on_red', attrs=['bold']) \ No newline at end of file + return ' ' + colored(code.strip().replace('\n', '\n ').replace('\t', ' '), None, 'on_red', attrs=['bold']) + + +# Given the results, exit with the appropriate status code +def exit_with_status_code(results): + num_issues = results.get('issues', 0) + if num_issues > 0: + exit(EXIT_CODE_ISSUES_FOUND) \ No newline at end of file