Skip to content

feat(python): add uv package manager support (TC-3855)#428

Open
a-oren wants to merge 4 commits intoguacsec:mainfrom
a-oren:TC-3855
Open

feat(python): add uv package manager support (TC-3855)#428
a-oren wants to merge 4 commits intoguacsec:mainfrom
a-oren:TC-3855

Conversation

@a-oren
Copy link
Copy Markdown
Contributor

@a-oren a-oren commented Apr 20, 2026

Summary

  • Add PythonUvProvider and PythonProviderFactory for automatic uv package manager detection via uv.lock presence
  • Dependency resolution uses uv pip list --format=json + uv pip show for CycloneDX SBOM generation (stack + component)
  • Extract shared TOML parsing into PyprojectTomlUtils, refactor both PythonPyprojectProvider and PythonUvProvider to use it
  • Fix PEP 508 extras stripping bug in getDependencyName() (e.g. requests[security]requests) affecting all Python providers
  • Document uv support, TRUSTIFY_DA_UV_PATH, and CLI examples in README

Test plan

  • mvn test -Dtest="Python_Uv_Provider_Test" -Dskip.junit_platform=true — 15 uv provider tests pass
  • mvn test -Dtest="Python_Pyproject_Provider_Test" -Dskip.junit_platform=true — 22 existing pyproject tests pass (regression)
  • mvn test -Dtest="PythonControllerRealEnvTest#get_Dependency_Name*" -Dskip.junit_platform=true — extras fix tests pass
  • mvn spotless:check — formatting passes
  • Manual CLI test: java -jar trustify-da-java-client-cli.jar sbom /path/to/uv-project/pyproject.toml produces correct CycloneDX SBOM

Acceptance Criteria

  • PythonProviderFactory.create() returns PythonUvProvider when uv.lock exists
  • PythonProviderFactory.create() falls back to PythonPyprojectProvider when no uv.lock
  • PythonUvProvider discovers uv binary via Operations.getExecutable("uv", "--version")
  • Custom binary path supported via TRUSTIFY_DA_UV_PATH
  • validateLockFile() throws IllegalStateException when uv.lock missing
  • provideStack() and provideComponent() generate valid CycloneDX SBOMs
  • Existing requirements.txt and pyproject.toml flows unchanged
  • #trustify-da-ignore / #exhortignore patterns work in uv context
  • README documents uv support

🤖 Generated with Claude Code

a-oren and others added 2 commits April 20, 2026 15:04
…ackage manager support

TC-3855

Add automatic detection and support for Python projects managed by the uv
package manager. When uv.lock is present alongside pyproject.toml, the new
PythonProviderFactory selects PythonUvProvider (using uv pip list/show for
dependency resolution) instead of the pip-based PythonPyprojectProvider.

- Add PythonProviderFactory with Map-based lock file detection pattern
- Add PythonUvProvider with CycloneDX SBOM generation (stack + component)
- Add PyprojectTomlUtils shared utility to deduplicate TOML parsing logic
- Refactor PythonPyprojectProvider to use PyprojectTomlUtils
- Fix PEP 508 extras stripping in getDependencyName (e.g. requests[security])
- Update Ecosystem.resolveProvider() to delegate to PythonProviderFactory
- Add test fixtures and 15 unit tests for the uv provider
- Document uv support, TRUSTIFY_DA_UV_PATH, and CLI examples in README

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Assisted-by: Claude Code
TC-3855

The PythonUvProvider unit tests require the uv binary to be available,
since the constructor eagerly validates it via Operations.getExecutable().
This follows the same pattern as other providers (cargo, go, gradle).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Assisted-by: Claude Code
@a-oren a-oren requested a review from ruromero April 20, 2026 13:14
@a-oren
Copy link
Copy Markdown
Contributor Author

a-oren commented Apr 21, 2026

/review

1 similar comment
@a-oren
Copy link
Copy Markdown
Contributor Author

a-oren commented Apr 21, 2026

/review

Copy link
Copy Markdown
Collaborator

@ruromero ruromero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR this one is not trivial. I made some comments.

return deps;
}

static String canonicalize(String name) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method is duplicated in PythonPyprojectProvider. It can be extracted to PyprojectTomlUtils

collectedIgnoredDeps = PyprojectTomlUtils.collectIgnoredDeps(manifestPath, getToml());
}

static final class UvPackage {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could implement this as a Record

}
}

static final class UvDependencyData {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, this is better implemented as a Record.

Comment thread README.md

##### uv Support

When a `uv.lock` file is present alongside `pyproject.toml`, the client automatically uses the [uv](https://docs.astral.sh/uv/) package manager for dependency resolution instead of pip. Dependency data is collected via `uv pip list --format=json` and `uv pip show`. No additional configuration is required — the provider is selected automatically based on lock file detection.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the JS implementation we use uv export --format requirements.txt --frozen --no-hashes --no-dev instead of uv pip list + uv pip show

https://github.com/guacsec/trustify-da-javascript-client/blob/main/src/providers/python_uv.js#L47

By using the --no-dev you skip dev deps which we don't scan and also you will use the uv.lock file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants