diff --git a/CHANGELOG.md b/CHANGELOG.md index 7453b3c6..7a2fa21c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). All versions prior to 0.0.9 are untracked. +## [Unreleased] + +### Added + +* CLI: The `--ignore-vuln` option has been added, allowing users to + specify PYSEC ids to ignore during the final report. + ([#275](https://github.com/trailofbits/pip-audit/pull/275)) + ## [2.2.1] - 2022-05-02 ### Fixed diff --git a/pip_audit/_cli.py b/pip_audit/_cli.py index 83789527..c05ecf47 100644 --- a/pip_audit/_cli.py +++ b/pip_audit/_cli.py @@ -287,6 +287,14 @@ def _parser() -> argparse.ArgumentParser: # argparse's default renderer uses __repr__ and produces # a pretty unpleasant help message. ) + parser.add_argument( + "--ignore-vuln", + type=str, + action="append", + dest="ignore_vuln", + default=[], + help="ignore a specific vulnerability by its PYSEC id", + ) return parser @@ -390,6 +398,7 @@ def audit() -> None: pkg_count = 0 vuln_count = 0 skip_count = 0 + vuln_ignore_count = 0 for (spec, vulns) in auditor.audit(source): if spec.is_skipped(): spec = cast(SkippedDependency, spec) @@ -401,6 +410,10 @@ def audit() -> None: else: spec = cast(ResolvedDependency, spec) state.update_state(f"Auditing {spec.name} ({spec.version})") + if args.ignore_vuln: + filtered_vulns = [v for v in vulns if v.id not in args.ignore_vuln] + vuln_ignore_count += len(vulns) - len(filtered_vulns) + vulns = filtered_vulns result[spec] = vulns if len(vulns) > 0: pkg_count += 1 @@ -442,7 +455,8 @@ def audit() -> None: if vuln_count > 0: summary_msg = ( f"Found {vuln_count} known " - f"{'vulnerability' if vuln_count == 1 else 'vulnerabilities'} " + f"{'vulnerability' if vuln_count == 1 else 'vulnerabilities'}" + f"{(vuln_ignore_count and ', ignored %d ' % vuln_ignore_count) or ' '}" f"in {pkg_count} {'package' if pkg_count == 1 else 'packages'}" ) if args.fix: @@ -457,7 +471,14 @@ def audit() -> None: if pkg_count != fixed_pkg_count: sys.exit(1) else: - print("No known vulnerabilities found", file=sys.stderr) + summary_msg = "No known vulnerabilities found" + if vuln_ignore_count: + summary_msg += f", {vuln_ignore_count} ignored" + + print( + summary_msg, + file=sys.stderr, + ) # If our output format is a "manifest" format we always emit it, # even if nothing other than a dependency summary is present. if skip_count > 0 or formatter.is_manifest: diff --git a/test/test_cli.py b/test/test_cli.py index c8c961b2..ad452640 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -10,9 +10,12 @@ ([], 1, 1, "Found 1 known vulnerability in 1 package"), ([], 2, 1, "Found 2 known vulnerabilities in 1 package"), ([], 2, 2, "Found 2 known vulnerabilities in 2 packages"), + (["--ignore-vuln", "bar"], 2, 2, "Found 2 known vulnerabilities, ignored 1 in 2 packages"), (["--fix"], 1, 1, "fixed 1 vulnerability in 1 package"), (["--fix"], 2, 1, "fixed 2 vulnerabilities in 1 package"), (["--fix"], 2, 2, "fixed 2 vulnerabilities in 2 packages"), + ([], 0, 0, "No known vulnerabilities found"), + (["--ignore-vuln", "bar"], 0, 1, "No known vulnerabilities found, 1 ignored"), ], ) def test_plurals(capsys, monkeypatch, args, vuln_count, pkg_count, expected): @@ -35,6 +38,9 @@ def test_plurals(capsys, monkeypatch, args, vuln_count, pkg_count, expected): for i in range(pkg_count) ] + if "--ignore-vuln" in args: + result[0][1].append(pretend.stub(id="bar")) + auditor = pretend.stub(audit=lambda a: result) monkeypatch.setattr(pip_audit._cli, "Auditor", lambda *a, **kw: auditor)