Skip to content

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

Merged
a-oren merged 4 commits into
guacsec:mainfrom
a-oren:TC-4332
May 31, 2026
Merged

feat(sbom): extract SHA-256 hashes from uv.lock for uv provider#533
a-oren merged 4 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 and attach SHA-256 hashes from uv.lock to uv dependency graph entries and propagate them into generated SBOMs for uv-managed projects.

New Features:

  • Include SHA-256 hashes from uv.lock (sdist or wheel entries) on uv provider dependency graph components and resulting SBOM output.

Tests:

  • Update uv provider golden SBOM fixture JSONs to cover hash population for components and stacks.

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

Adds SHA-256 hash extraction from uv.lock for uv-managed Python projects and wires it into the uv dependency graph so CycloneDX SBOMs include per-component hashes, updating uv golden fixtures accordingly.

Sequence diagram for uv dependency data retrieval with hash attachment

sequenceDiagram
    participant Caller
    participant Python_uv
    participant UvExport
    participant UvLock

    Caller->>Python_uv: _getDependencyData(manifestDir, workspaceDir, parsed, opts)
    Python_uv->>Python_uv: _getProjectName(parsed)
    Python_uv->>UvExport: _getUvExportOutput(manifestDir, opts)
    Python_uv->>Python_uv: _parseUvExport(uvOutput, projectName, workspaceDir)
    activate Python_uv
    Python_uv-->>Python_uv: directDeps, graph
    deactivate Python_uv
    Python_uv->>UvLock: _attachHashesFromLockFile(workspaceDir/uv.lock, graph)
    activate UvLock
    UvLock->>UvLock: fs.readFileSync(lockFilePath, utf-8)
    UvLock->>UvLock: parseToml(lockContent)
    UvLock-->>Python_uv: graph entries updated with hashes
    deactivate UvLock
    Python_uv-->>Caller: { directDeps, graph }
Loading

File-Level Changes

Change Details Files
Attach SHA-256 hashes from uv.lock packages to uv dependency graph entries and update uv SBOM fixtures to assert hash output.
  • Extend _getDependencyData to invoke a new helper that reads uv.lock after parsing uv export and enriches graph entries before returning dependency data.
  • Introduce _attachHashesFromLockFile to synchronously read and TOML-parse uv.lock, iterate package entries, derive a sha256 hash from sdist.hash or wheels[0].hash, and populate a hashes array on matching graph entries when absent.
  • Canonicalize uv.lock package names to match graph keys and skip packages lacking names, hashes, or non-sha256 hashes, with basic error logging on read/parse failures.
  • Update all uv-related expected_component_sbom.json and expected_stack_sbom.json fixtures so components now include hashes arrays aligned with the new graph data.
src/providers/python_uv.js
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

@ruromero
Copy link
Copy Markdown
Collaborator

@sourcery-ai review

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 JSDoc types for the graph entry are inconsistent: the return type in _getDependencyData uses import('./base_pyproject.js').default.GraphEntry while _attachHashesFromLockFile uses import('./base_pyproject.js').GraphEntry, which should be aligned to the actual export to avoid tooling/type issues.
  • Consider avoiding fs.readFileSync and console.error in _attachHashesFromLockFile for better integration with the existing async flow and logging approach (e.g. use async I/O and the existing logger or a debug flag so SBOM generation doesn’t spam stderr on missing or malformed uv.lock files).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The JSDoc types for the graph entry are inconsistent: the return type in `_getDependencyData` uses `import('./base_pyproject.js').default.GraphEntry` while `_attachHashesFromLockFile` uses `import('./base_pyproject.js').GraphEntry`, which should be aligned to the actual export to avoid tooling/type issues.
- Consider avoiding `fs.readFileSync` and `console.error` in `_attachHashesFromLockFile` for better integration with the existing async flow and logging approach (e.g. use async I/O and the existing logger or a debug flag so SBOM generation doesn’t spam stderr on missing or malformed `uv.lock` files).

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.

Align JSDoc GraphEntry type import, use async I/O instead of
readFileSync, and remove console.error calls in _attachHashesFromLockFile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ruromero
Copy link
Copy Markdown
Collaborator

Verification Report for TC-4332 (commit 424e569)

Check Result Details
Review Feedback N/A No inline review comment threads; bot review suggestions already addressed
Root-Cause Investigation N/A No sub-tasks created
Scope Containment PASS 1 source file matches task spec; 14 test fixtures expected per Test Requirements
Diff Size PASS +40/-2 source, ~780/314 fixture updates; proportionate to task scope
Commit Traceability PASS 3/3 meaningful commits reference TC-4332
Sensitive Patterns PASS No secrets detected; hex strings are public PyPI package checksums
CI Status PASS All 5 checks pass (lint, test Node 22/24, PR title, commit messages)
Acceptance Criteria PASS 4 of 4 criteria met
Test Quality N/A No test source files modified; only golden SBOM fixture JSON updates
Test Change Classification ADDITIVE Hash data added to 14 golden fixtures; no assertions weakened
Verification Commands N/A None specified in task

Overall: PASS

All acceptance criteria satisfied. The _attachHashesFromLockFile method correctly extracts SHA-256 hashes from uv.lock TOML entries, strips the sha256: prefix, and attaches them to graph entries. All 14 golden SBOM fixtures updated with hash data across all uv test variants (uv_lock, uv_self_ref, uv_dev_deps, uv_workspace including sub-packages). CI passes on both Node 22 and 24.


This comment was AI-generated by sdlc-workflow/verify-pr v0.9.1.

@a-oren a-oren merged commit 6645ba5 into guacsec:main May 31, 2026
5 checks passed
@a-oren a-oren deleted the TC-4332 branch May 31, 2026 05:55
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