Skip to content

feat(sbom): extract SHA-256 hashes from uv.lock for uv provider#533

Open
a-oren wants to merge 3 commits into
guacsec:mainfrom
a-oren:TC-4332
Open

feat(sbom): extract SHA-256 hashes from uv.lock for uv provider#533
a-oren wants to merge 3 commits into
guacsec:mainfrom
a-oren:TC-4332

Conversation

@a-oren
Copy link
Copy Markdown
Contributor

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

Summary

  • Parse uv.lock TOML to extract SHA-256 artifact hashes (from sdist.hash or wheels[0].hash) and attach them to dependency graph entries
  • Generated CycloneDX SBOMs now include per-component hashes arrays for uv-managed projects
  • Updated all 14 uv golden SBOM fixtures with hash data

Implements TC-4332

Test plan

  • All 31 uv provider tests pass with updated golden files
  • No regressions in other providers (434 passing, 19 pre-existing failures unrelated to this change)
  • ESLint passes on modified source

🤖 Generated with Claude Code

Summary by Sourcery

Extract SHA-256 hashes from uv.lock and attach them to uv dependency graph entries so generated SBOMs include per-component hash metadata.

New Features:

  • Populate dependency graph entries with SHA-256 hashes parsed from uv.lock for uv-managed Python projects.
  • Include per-component hash arrays in generated CycloneDX SBOMs for uv projects.

Tests:

  • Update uv provider SBOM golden fixtures to cover hash extraction and serialization in component and stack SBOMs.

Parse uv.lock TOML to extract SHA-256 artifact hashes (from sdist or
wheels entries) and attach them to the dependency graph, so generated
CycloneDX SBOMs include per-component hash data. This enables the
backend to compare artifact SHAs against the Trusted Libraries registry.

Implements TC-4332

Assisted-by: Claude Code
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 20, 2026

Reviewer's Guide

This PR extends the Python uv provider to read SHA-256 hashes from uv.lock and attach them to dependency graph entries, updating the CycloneDX SBOM output and corresponding uv-related golden fixtures.

Sequence diagram for uv provider dependency resolution with uv.lock hash attachment

sequenceDiagram
    participant Python_uv
    participant UvExport as _getUvExportOutput
    participant UvParse as _parseUvExport
    participant Fs as fs
    participant Toml as parseToml

    Python_uv->>UvExport: _getUvExportOutput(manifestDir, opts)
    UvExport-->>Python_uv: uvOutput

    Python_uv->>UvParse: _parseUvExport(uvOutput, projectName, workspaceDir)
    UvParse-->>Python_uv: directDeps, graph

    Python_uv->>Fs: readFileSync(workspaceDir/uv.lock, utf-8)
    alt lock file readable
        Fs-->>Python_uv: lockContent
        Python_uv->>Toml: parseToml(lockContent)
        alt TOML parsed
            Toml-->>Python_uv: parsed
            Python_uv->>Python_uv: _attachHashesFromLockFile(lockFilePath, graph)
        else parse error
            Toml-->>Python_uv: [throw]
        end
    else missing lock file
        Fs-->>Python_uv: [throw]
    end

    Python_uv-->>Python_uv: return {directDeps, graph}
Loading

File-Level Changes

Change Details Files
Attach SHA-256 hashes from uv.lock to uv dependency graph entries
  • Update _getDependencyData to call a new helper after parsing uv export and return the augmented graph type-safe via the Base_pyproject.GraphEntry typedef
  • Implement _attachHashesFromLockFile to read uv.lock, parse it as TOML, and safely handle missing files or parse errors
  • Extract per-package hashes from either sdist.hash or the first wheels[0].hash when prefixed with 'sha256:' and attach them as hashes arrays on matching graph entries, keyed by canonicalized package name
src/providers/python_uv.js
Update uv provider SBOM golden fixtures to include hashes arrays
  • Adjust expected_component_sbom.json and expected_stack_sbom.json fixtures across uv-related test manifets to include per-component SHA-256 hashes in the CycloneDX output
  • Keep existing dependency structures intact while only extending components with the new hashes field
test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_component_sbom.json
test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_stack_sbom.json
test/providers/tst_manifests/pyproject/uv_dev_deps/expected_component_sbom.json
test/providers/tst_manifests/pyproject/uv_dev_deps/expected_stack_sbom.json
test/providers/tst_manifests/pyproject/uv_lock/expected_component_sbom.json
test/providers/tst_manifests/pyproject/uv_lock/expected_stack_sbom.json
test/providers/tst_manifests/pyproject/uv_self_ref/expected_component_sbom.json
test/providers/tst_manifests/pyproject/uv_self_ref/expected_stack_sbom.json
test/providers/tst_manifests/pyproject/uv_workspace/expected_component_sbom.json
test/providers/tst_manifests/pyproject/uv_workspace/expected_stack_sbom.json
test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_component_sbom.json
test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_stack_sbom.json
test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_component_sbom.json
test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_stack_sbom.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@a-oren a-oren requested a review from ruromero May 20, 2026 11:58
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The new _attachHashesFromLockFile helper silently ignores both file read and TOML parse errors; consider at least debug-level logging so issues with malformed or missing uv.lock files are discoverable during troubleshooting.
  • The JSDoc for _attachHashesFromLockFile still describes the graph entries as {name, version, children} while _getDependencyData now documents GraphEntry; it would be good to align this type annotation with the actual GraphEntry shape to avoid confusion.
  • When attaching hashes, the code overwrites entry.hashes unconditionally; if other parts of the pipeline might already populate hashes, you may want to append or merge rather than replace to avoid losing existing data.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `_attachHashesFromLockFile` helper silently ignores both file read and TOML parse errors; consider at least debug-level logging so issues with malformed or missing `uv.lock` files are discoverable during troubleshooting.
- The JSDoc for `_attachHashesFromLockFile` still describes the `graph` entries as `{name, version, children}` while `_getDependencyData` now documents `GraphEntry`; it would be good to align this type annotation with the actual `GraphEntry` shape to avoid confusion.
- When attaching hashes, the code overwrites `entry.hashes` unconditionally; if other parts of the pipeline might already populate hashes, you may want to append or merge rather than replace to avoid losing existing data.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

a-oren added 2 commits May 20, 2026 15:01
- Log errors when uv.lock cannot be read or parsed instead of silently
  ignoring, so issues are discoverable during troubleshooting
- Align JSDoc graph parameter type with GraphEntry typedef
- Skip hash assignment when entry already has hashes to avoid
  overwriting data from other pipeline stages

Implements TC-4332

Assisted-by: Claude Code
@a-oren
Copy link
Copy Markdown
Contributor Author

a-oren commented May 20, 2026

/review

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.

1 participant