diff --git a/CHANGELOG.md b/CHANGELOG.md index 37902279..59428d3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ All versions prior to 0.0.9 are untracked. ## [Unreleased] +### Changed + +* Improved error message for when unpinned URL requirements are found during an + audit with the `--no-deps` flag + ([#355](https://github.com/trailofbits/pip-audit/pull/355)) + ### Fixed * Fixed an issue where packages on PyPI with no published versions trigger a diff --git a/pip_audit/_dependency_source/requirement.py b/pip_audit/_dependency_source/requirement.py index d4a1b25c..92a97f1e 100644 --- a/pip_audit/_dependency_source/requirement.py +++ b/pip_audit/_dependency_source/requirement.py @@ -251,7 +251,15 @@ def _collect_preresolved_deps( ) if not req.specifier: - raise RequirementSourceError(f"requirement {req.name} is not pinned: {str(req)}") + if req.link is None: + raise RequirementSourceError( + f"requirement {req.name} is not pinned: {str(req)}" + ) + else: + raise RequirementSourceError( + f"requirement {req.name} is not pinned, URL requirements must be pinned " + f"with #egg=your_package_name==your_package_version: {str(req)}" + ) pinned_specifier = PINNED_SPECIFIER_RE.match(str(req.specifier)) if pinned_specifier is None: diff --git a/test/dependency_source/test_requirement.py b/test/dependency_source/test_requirement.py index 786cb272..c916791c 100644 --- a/test/dependency_source/test_requirement.py +++ b/test/dependency_source/test_requirement.py @@ -443,6 +443,23 @@ def test_requirement_source_no_deps_unpinned(monkeypatch): list(source.collect()) +def test_requirement_source_no_deps_unpinned_url(monkeypatch): + source = requirement.RequirementSource( + [Path("requirements.txt")], ResolveLibResolver(), no_deps=True + ) + + monkeypatch.setattr( + pip_requirements_parser, + "get_file_content", + lambda _: "https://github.com/pallets/flask/archive/refs/tags/2.0.1.tar.gz#egg=flask\n" + "requests>=1.0", + ) + + # When dependency resolution is disabled, all requirements must be pinned. + with pytest.raises(DependencySourceError): + list(source.collect()) + + def test_requirement_source_dep_caching(monkeypatch): source = requirement.RequirementSource( [Path("requirements.txt")], ResolveLibResolver(), no_deps=True