diff --git a/scripts/vulnerability_report.py b/scripts/vulnerability_report.py index 4cc0d35db..b541919b6 100644 --- a/scripts/vulnerability_report.py +++ b/scripts/vulnerability_report.py @@ -7,9 +7,11 @@ repositories. # Usage: -usage: vulnerability_report.py [-h] [-v] --organization ORGANIZATION - --repository REPOSITORY [-r] [-g] [-p] - [-c COMPARISON [COMPARISON ...]] +usage: vulnerability_report.py [-h] [-v] [--organization ORGANIZATION] + [--repository REPOSITORY] [-r] + [-s {auto_dismissed,dismissed,fixed,open}] [-a] + [-g] [-svg] [-png] [-p] + [-c COMPARISON [COMPARISON ...]] Vulnerability report tool @@ -22,6 +24,8 @@ GitHub repository. -r, --retrieve-issues Retrieve issues + -s, --state {auto_dismissed,dismissed,fixed,open} + Filter just issues with specified state during retrieval -a, --all-actions Retrieve issues for all LCore repositories, generates graphs and reports -g, --generate-graphs Generate graphs with vulnerabilities info @@ -41,7 +45,7 @@ from collections import Counter from datetime import datetime from statistics import median -from typing import Any +from typing import Any, Optional import matplotlib.pyplot as plt import pandas as pd @@ -103,6 +107,14 @@ def create_argument_parser() -> ArgumentParser: help="Retrieve issues", ) + cli_parser.add_argument( + "-s", + "--state", + default=None, + choices=["auto_dismissed", "dismissed", "fixed", "open"], + help="Filter just issues with specified state during retrieval", + ) + cli_parser.add_argument( "-a", "--all-actions", @@ -745,7 +757,12 @@ def is_valid_github_org_repo(name: str) -> bool: return bool(re.fullmatch(r"[A-Za-z0-9_.-]+", name)) -def retrieve_issues(organization: str, repository: str, dependabot_file: str) -> int: +def retrieve_issues( + organization: str, + repository: str, + dependabot_file: str, + state_filter: Optional[str], +) -> int: """ Retrieve all Dependabot alerts for a GitHub repository and save them to a JSON file. @@ -780,9 +797,9 @@ def retrieve_issues(organization: str, repository: str, dependabot_file: str) -> print("Repository name is not correct") return 2 - TOKEN = os.environ.get("GITHUB_TOKEN") + GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN") - if TOKEN is None: + if GITHUB_TOKEN is None: print("GITHUB_TOKEN environment variable must be set!") return 1 @@ -793,8 +810,13 @@ def retrieve_issues(organization: str, repository: str, dependabot_file: str) -> url = f"https://api.github.com/repos/{organization}/{repository}/dependabot/alerts" + request_params = {} + + if state_filter is not None: + request_params["state"] = state_filter + headers = { - "Authorization": f"Bearer {TOKEN}", + "Authorization": f"Bearer {GITHUB_TOKEN}", "Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28", } @@ -806,7 +828,18 @@ def retrieve_issues(organization: str, repository: str, dependabot_file: str) -> try: while url: print("Retrieving data from URL:", url) - r = requests.get(url, headers=headers, timeout=10) + r = requests.get( + url, headers=headers, timeout=10, params=request_params + ) + + # params with state filter need to be passed just for the 1st call + # when paginating through Dependabot alerts, request_params + # (containing the state filter) is re-sent on every iteration + # of the while url loop. GitHub pagination Link headers return + # fully-qualified next-page URLs that already include query + # parameters. + request_params = {} + r.raise_for_status() data = r.json() @@ -839,6 +872,7 @@ def retrieve_issues(organization: str, repository: str, dependabot_file: str) -> def process_issues_for_repository( organization: str, repository: str, + state_filter: Optional[str], dependabot_file: str, svg_output: bool, png_output: bool, @@ -851,6 +885,7 @@ def process_issues_for_repository( Parameters: organization (str): name of GitHub organization repository (str): name of GitHub repository + state_filter (str): used to filter issues with specified state dependabot_file (str): file to store Dependabot issues svg_output (bool): if set to true, CVE statistic is exported into SVG graphs png_output (bool): if set to true, CVE statistic is exported into PNG graphs @@ -865,7 +900,9 @@ def process_issues_for_repository( result = 0 if retrieve_issues_operation: # retrieve issues - result += retrieve_issues(organization, repository, dependabot_file) + result += retrieve_issues( + organization, repository, dependabot_file, state_filter + ) if result > 0: print("Error retrieving issues") @@ -923,6 +960,7 @@ def main() -> int: errors += process_issues_for_repository( organization, repository, + args.state, dependabot_file, args.svg_output, args.png_output, @@ -935,6 +973,7 @@ def main() -> int: return process_issues_for_repository( args.organization, args.repository, + args.state, dependabot_file, args.svg_output, args.png_output,