Skip to content

Commit

Permalink
_dependency_source/pip: Log a warning and skip auditing for packages …
Browse files Browse the repository at this point in the history
…with invalid versions (#139)

* _dependency_source/pip: Log warning when attempting to audit a package
with an invalid version

* test: Add unit test for versions that don't conform to PEP 440

* test: Avoid constructing `LegacyVersion` objects
  • Loading branch information
tetsuo-cpp authored Nov 29, 2021
1 parent 1c69d2d commit 3790b1c
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
20 changes: 13 additions & 7 deletions pip_audit/_dependency_source/pip.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Iterator, Optional

import pip_api
from packaging.version import Version
from packaging.version import InvalidVersion, Version

from pip_audit._dependency_source import DependencySource, DependencySourceError
from pip_audit._service import Dependency
Expand Down Expand Up @@ -62,12 +62,18 @@ def collect(self) -> Iterator[Dependency]:
# We collect them all into a single well-defined error.
try:
for (_, dist) in pip_api.installed_distributions(local=self._local).items():
dep = Dependency(name=dist.name, version=Version(str(dist.version)))
if self.state is not None:
self.state.update_state(
f"Collecting {dep.name} ({dep.version})"
) # pragma: no cover
yield dep
try:
dep = Dependency(name=dist.name, version=Version(str(dist.version)))
if self.state is not None:
self.state.update_state(
f"Collecting {dep.name} ({dep.version})"
) # pragma: no cover
yield dep
except InvalidVersion:
logger.warning(
"Warning: Package has invalid version and could not be audited: "
f"{dist.name} ({dist.version})"
)
except Exception as e:
raise PipSourceError("failed to list installed distributions") from e

Expand Down
32 changes: 32 additions & 0 deletions test/dependency_source/test_pip.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from dataclasses import dataclass
from typing import Dict

import pip_api
import pretend
import pytest
Expand Down Expand Up @@ -43,3 +46,32 @@ def explode():

with pytest.raises(pip.PipSourceError):
list(source.collect())


def test_pip_source_invalid_version(monkeypatch):
logger = pretend.stub(warning=pretend.call_recorder(lambda s: None))
monkeypatch.setattr(pip, "logger", logger)

source = pip.PipSource()

@dataclass(frozen=True)
class MockDistribution:
name: str
version: str

# Return a distribution with a version that doesn't conform to PEP 440.
# We should log a warning and skip it.
def mock_installed_distributions(local: bool) -> Dict[str, MockDistribution]:
return {
"pytest": MockDistribution("pytest", "0.1"),
"pip-audit": MockDistribution("pip-audit", "1.0-ubuntu0.21.04.1"),
"pip-api": MockDistribution("pip-api", "1.0"),
}

monkeypatch.setattr(pip_api, "installed_distributions", mock_installed_distributions)

specs = list(source.collect())
assert len(logger.warning.calls) == 1
assert len(specs) == 2
assert Dependency(name="pytest", version=Version("0.1")) in specs
assert Dependency(name="pip-api", version=Version("1.0")) in specs

0 comments on commit 3790b1c

Please sign in to comment.