Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions guarddog/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,19 @@ def _scan(
else:
log.debug(f"Considering that '{identifier}' is a remote target")
result |= scanner.scan_remote(identifier, version, rule_param)

scanned_version = version
if version is None and ecosystem == ECOSYSTEM.PYPI:
from guarddog.utils.package_info import get_package_info
try:
package_info = get_package_info(identifier)
scanned_version = package_info["info"]["version"]
except Exception:
pass

result["is_remote"] = True
result["ecosystem"] = ecosystem
result["scanned_version"] = scanned_version
except Exception as e:
log.error(f"Error occurred while scanning target {identifier}: '{e}'\n")
sys.exit(1)
Expand Down
10 changes: 10 additions & 0 deletions guarddog/reporters/human_readable.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ def _format_code_line_for_output(code) -> str:
)
lines.append("")

if (
num_issues > 0
and results.get("is_remote")
and results.get("ecosystem") == ECOSYSTEM.PYPI
):
scanned_version = results.get("scanned_version")
if scanned_version:
inspector_url = f"https://inspector.pypi.io/project/{safe_identifier}/{scanned_version}"
lines.append(f"For more details, see: {inspector_url}")

return "\n".join(lines)

@staticmethod
Expand Down
76 changes: 76 additions & 0 deletions tests/reporters/test_human_readable.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import re

from guarddog.reporters.human_readable import HumanReadableReporter, _sanitize
from guarddog.ecosystems import ECOSYSTEM

# Strips ANSI SGR/CSI/OSC sequences emitted by termcolor so assertions can match
# the underlying text instead of color codes.
Expand Down Expand Up @@ -157,3 +158,78 @@ def test_print_scan_results_benign_input_is_preserved():
assert "matched a benign-looking pattern" in plain
assert "requests" in plain
assert "rule-name" in plain


def test_pypi_inspector_link_shown_for_remote_pypi_with_issues():
results = {
"issues": 1,
"errors": {},
"results": {
"some-rule": "found suspicious behavior"
},
"is_remote": True,
"ecosystem": ECOSYSTEM.PYPI,
"scanned_version": "2.28.1"
}
out = HumanReadableReporter.print_scan_results("requests", results)
plain = _strip_color(out)
assert "https://inspector.pypi.io/project/requests/2.28.1" in plain


def test_pypi_inspector_link_not_shown_for_local_scan():
results = {
"issues": 1,
"errors": {},
"results": {
"some-rule": "found suspicious behavior"
}
}
out = HumanReadableReporter.print_scan_results("requests", results)
plain = _strip_color(out)
assert "inspector.pypi.io" not in plain


def test_pypi_inspector_link_not_shown_when_no_issues():
results = {
"issues": 0,
"errors": {},
"results": {},
"is_remote": True,
"ecosystem": ECOSYSTEM.PYPI,
"scanned_version": "2.28.1"
}
out = HumanReadableReporter.print_scan_results("requests", results)
plain = _strip_color(out)
assert "inspector.pypi.io" not in plain


def test_pypi_inspector_link_not_shown_for_npm():
results = {
"issues": 1,
"errors": {},
"results": {
"some-rule": "found suspicious behavior"
},
"is_remote": True,
"ecosystem": ECOSYSTEM.NPM,
"scanned_version": "1.0.0"
}
out = HumanReadableReporter.print_scan_results("lodash", results)
plain = _strip_color(out)
assert "inspector.pypi.io" not in plain


def test_pypi_inspector_link_not_shown_when_version_is_none():
results = {
"issues": 1,
"errors": {},
"results": {
"some-rule": "found suspicious behavior"
},
"is_remote": True,
"ecosystem": ECOSYSTEM.PYPI,
"scanned_version": None
}
out = HumanReadableReporter.print_scan_results("requests", results)
plain = _strip_color(out)
assert "inspector.pypi.io" not in plain