A tool for scanning Python environments for known vulnerabilities
—
Various sources of Python dependencies including pip environments, requirements files, pyproject.toml files, and lock files. Dependency sources provide the packages to be audited and can optionally apply fixes.
Abstract base class for all dependency sources.
class DependencySource(ABC):
"""
Represents an abstract source of fully-resolved Python dependencies.
Individual concrete dependency sources are expected to subclass DependencySource
and implement it in their terms.
"""
@abstractmethod
def collect(self) -> Iterator[Dependency]:
"""
Yield the dependencies in this source.
Returns:
Iterator of Dependency objects
"""
@abstractmethod
def fix(self, fix_version: ResolvedFixVersion) -> None:
"""
Upgrade a dependency to the given fix version.
Parameters:
- fix_version: ResolvedFixVersion, the version to upgrade to
"""Source that collects dependencies from the current pip environment.
class PipSource(DependencySource):
"""
Wraps pip (specifically pip list) as a dependency source.
"""
def __init__(
self,
*,
local: bool = False,
paths: Sequence[Path] = [],
skip_editable: bool = False,
state: AuditState = AuditState(),
):
"""
Create a new PipSource.
Parameters:
- local: bool, whether to include only local packages
- paths: Sequence[Path], additional paths to include
- skip_editable: bool, whether to skip editable packages
- state: AuditState, state tracker for progress updates
"""
def collect(self) -> Iterator[Dependency]:
"""Collect dependencies from pip list."""
def fix(self, fix_version: ResolvedFixVersion) -> None:
"""Fix a dependency by upgrading via pip install."""Source that reads dependencies from requirements.txt files.
class RequirementSource(DependencySource):
"""
Dependency source for requirements.txt style files.
"""
def __init__(
self,
filenames: list[Path],
*,
require_hashes: bool = False,
no_deps: bool = False,
disable_pip: bool = False,
skip_editable: bool = False,
index_url: str | None = None,
extra_index_urls: list[str] = [],
state: AuditState = AuditState(),
) -> None:
"""
Create a new RequirementSource.
Parameters:
- filenames: list[Path], list of filepaths to parse
- require_hashes: bool, controls the hash policy
- no_deps: bool, whether to skip dependency resolution
- disable_pip: bool, whether to disable pip for resolution
- skip_editable: bool, whether to skip editable packages
- index_url: str | None, custom index URL
- extra_index_urls: list[str], additional index URLs
- state: AuditState, state tracker for progress updates
"""
def collect(self) -> Iterator[Dependency]:
"""Collect dependencies from requirements file."""
def fix(self, fix_version: ResolvedFixVersion) -> None:
"""Fix a dependency by updating the requirements file."""Source that reads dependencies from pyproject.toml files.
class PyProjectSource(DependencySource):
"""
Dependency source for pyproject.toml files.
"""
def __init__(
self,
filename: Path,
index_url: str | None = None,
extra_index_urls: list[str] = [],
state: AuditState = AuditState(),
) -> None:
"""
Create a new PyProjectSource.
Parameters:
- filename: Path, path to a pyproject.toml file
- index_url: str | None, base URL of the package index
- extra_index_urls: list[str], extra URLs of package indexes
- state: AuditState, state tracker for progress updates
"""
def collect(self) -> Iterator[Dependency]:
"""Collect dependencies from pyproject.toml."""
def fix(self, fix_version: ResolvedFixVersion) -> None:
"""Fix a dependency by updating pyproject.toml."""Source that reads dependencies from Python lock files.
class PyLockSource(DependencySource):
"""
Dependency source for Python lock files (poetry.lock, Pipfile.lock, etc.).
"""
def __init__(self, filenames: list[Path]) -> None:
"""
Create a new PyLockSource.
Parameters:
- filenames: list[Path], list of pylock.*.toml files to parse
"""
def collect(self) -> Iterator[Dependency]:
"""Collect dependencies from lock file."""
def fix(self, fix_version: ResolvedFixVersion) -> None:
"""Fix a dependency by updating the lock file."""Exceptions raised by dependency sources.
class DependencySourceError(Exception):
"""
Raised when a DependencySource fails to provide its dependencies.
"""
class DependencyFixError(Exception):
"""
Raised when a DependencySource fails to perform a fix operation.
"""
class InvalidRequirementSpecifier(DependencySourceError):
"""
A DependencySourceError specialized for non-PEP 440 requirements specifiers.
"""
class PipSourceError(DependencySourceError):
"""
Pip-specific dependency source errors.
"""
class PipFixError(DependencyFixError):
"""
Pip-specific dependency fix errors.
"""
class RequirementSourceError(DependencySourceError):
"""
Requirements file-specific dependency source errors.
"""
class RequirementFixError(DependencyFixError):
"""
Requirements file-specific dependency fix errors.
"""
class PyProjectSourceError(DependencySourceError):
"""
PyProject-specific dependency source errors.
"""
class PyProjectFixError(DependencyFixError):
"""
PyProject-specific dependency fix errors.
"""
class PyLockSourceError(DependencySourceError):
"""
Lock file-specific dependency source errors.
"""
class PyLockFixError(DependencyFixError):
"""
Lock file-specific dependency fix errors.
"""PYPI_URL: str = "https://pypi.org/simple/"
"""Default PyPI simple index URL."""from pip_audit._dependency_source import PipSource
# Audit current pip environment
source = PipSource()
dependencies = list(source.collect())
print(f"Found {len(dependencies)} packages in environment")from pip_audit._dependency_source import RequirementSource
# Audit a requirements file
source = RequirementSource("requirements.txt")
dependencies = list(source.collect())
print(f"Found {len(dependencies)} packages in requirements.txt")from pip_audit._dependency_source import PipSource, PyProjectSource
from pip_audit._audit import Auditor
from pip_audit._service import PyPIService
service = PyPIService()
auditor = Auditor(service=service)
# Audit multiple sources
sources = [
PipSource(local=True),
PyProjectSource("pyproject.toml"),
]
for i, source in enumerate(sources):
print(f"Auditing source {i+1}:")
for dependency, vulns in auditor.audit(source):
if vulns:
print(f" {dependency.name}: {len(vulns)} vulnerabilities")Install with Tessl CLI
npx tessl i tessl/pypi-pip-audit