Skip to content

Source-aware license resolution for uv projects: editables, private indexes, exact artifacts - #151

Open
joshuanapoli wants to merge 14 commits into
FHPythonUtils:masterfrom
joshuanapoli:fix/editable-local-dependencies
Open

Source-aware license resolution for uv projects: editables, private indexes, exact artifacts#151
joshuanapoli wants to merge 14 commits into
FHPythonUtils:masterfrom
joshuanapoli:fix/editable-local-dependencies

Conversation

@joshuanapoli

@joshuanapolijoshuanapoli commented Jul 30, 2026

Copy link
Copy Markdown

Purpose of This Pull Request

  • Documentation update
  • Bug fix
  • New feature
  • Other

Overview of Changes

This change gets the latest LicenseCheck to work with our monorepo. LicenseCheck was crashing because of the "pip-style editable entries".

It's also an attempt to tighten up our long list of "ignore_packages", by trying harder to understand the analyzed licenses and providing a more exact way to work around dependencies with incorrect or missing license metadata.

Audit editable and local path dependencies

LicenseCheck previously crashed when uv emitted pip-style editable entries such as:

-e ../../libs/anomaly_detection

Declares requirements-parser directly (already present transitively via depgather); uv emits pip-style requirements files whose -e <path> lines are not valid PEP 508 requirements. Passing them directly to packaging.Requirement raised InvalidRequirement.

This change:

  • Resolves active editable paths relative to the project being checked.
  • Reads each local project's name, version, author, URLs, and license from its own pyproject.toml.
  • Adds editable projects back to the audited dependency set as pinned requirements.
  • Recursively follows nested [tool.uv.sources] paths and uv workspace members.
  • Leaves configured but inactive local sources out of the audit.
  • Handles cycles, paths containing spaces, and projects whose directory and package names differ.

Audit locked versions

  • Exports an adjacent uv.lock instead of re-resolving the project.
  • Preserves exact resolved version strings for reporting and version-scoped policy rules.
  • Requests metadata for the exact package version instead of silently falling back to the latest release.
  • Honors the project's uv prerelease setting when resolution is necessary.

Support private indexes and exact artifact metadata

  • Uses uv's configured indexes and credentials to retrieve private package wheels.
  • Falls back to the exact wheel's METADATA when public PyPI is unavailable or omits usable license metadata.
  • Ignores installed metadata when the installed package version differs from the resolved version.

Partially addresses #95 and #128 by delegating package-index selection and authentication to uv.

Fixes#121 by reading the PEP 639 License-Expression field from local and downloaded artifact metadata.

Fixes#150.

Make policy evaluation safer

  • Supports package==version entries in ignore_packages and fail_packages.
  • Ensures an explicitly failed license cannot be masked by another compatible license on the same package.
  • Treats missing and unknown licenses as incompatible instead of crashing while indexing the compatibility matrix.
  • Preserves uv resolution errors for pyproject.toml rather than falling back to a less accurate parser.
  • Accepts dependencies whose custom license reference exactly matches the project's custom license reference.
  • Adds allowed_license_references / --allowed-license-references for explicitly accepting exact raw LicenseRef-* identifiers without allowing the generic proprietary-license category. Package and license deny rules retain precedence.
  • Prefers recognizable explicit legacy license metadata—SPDX expressions, exact LicenseRef-* identifiers, and conservative aliases such as Apache 2.0—over less-specific classifiers. Unrecognized legacy text continues to fall back to classifiers.
  • Safely normalizes SPDX WITH expressions without assuming every parsed expression has a .key attribute.

This precedence handles packages that publish a specific license in License alongside a generic or incorrect Trove classifier, including NVIDIA packages whose LicenseRef-NVIDIA-Proprietary or Apache 2.0 metadata was previously hidden by Other/Proprietary License.

Fixes#137.

Audit reviewed metadata overrides

Projects can supply a reviewed license when an exact artifact publishes missing, ambiguous, or incorrect metadata:

[tool.licensecheck.license_overrides]
"sample==1.2.3" = "BSD-3-Clause"
  • Override keys must use an exact name==version; ranges, wildcards, markers, extras, URLs, and unversioned names are rejected.
  • The package remains in the audit and the substituted license is evaluated by the normal package and license allow/deny rules.
  • Human-readable and structured output identify affected packages with licenseSource = "configured override".
  • A dependency update cannot silently inherit a review performed for an older artifact.

This provides a safer alternative to ignore_packages for reviewed packages with defective upstream metadata, without guessing from license text or maintaining package-specific rules in LicenseCheck.

License-matrix indexing fix

liceCompat indexed matrix.csv by list(License) position, but enum order and CSV order diverge for UPL_1/NCSA/PSFL; it now looks rows and columns up by name. Independent correctness fix, worth its own bullet.

Subprocess hardening

stdin=DEVNULL plus timeouts on both uv calls, so a private-index credential prompt can't hang a worker thread forever; artifact-fetch and resolver-fallback failures now log.

Performance

The SPDX licensing index is cached instead of rebuilt per license string, index discovery happens once per requirements file rather than once per requirement, and a duplicate uv pip install on the artifact-failure path was removed.

Testing

  • uv run pytest tests/test_packageinfo.py -q — 45 passed
  • uv run pytest -q -k 'not ansi' — 124 passed, 3 deselected
  • Ruff formatting and lint checks pass for the changed files
  • An authenticated scan of a multi-project uv monorepo, including private indexes, editable local libraries, allowed NVIDIA license references, and four exact-version metadata overrides, reports no failing packages

@joshuanapolijoshuanapoli changed the title Handle editable uv path dependenciesSource-aware license resolution for uv projects: editables, private indexes, exact artifactsAug 1, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@joshuanapoli