Skip to content

fix: update mixed case dependencies in python to be normalized#4573

Merged
spiffcs merged 2 commits intomainfrom
4562-poetry-bug
Jan 27, 2026
Merged

fix: update mixed case dependencies in python to be normalized#4573
spiffcs merged 2 commits intomainfrom
4562-poetry-bug

Conversation

@spiffcs
Copy link
Contributor

@spiffcs spiffcs commented Jan 26, 2026

Description

When generating a CycloneDX SBOM from a Python project that uses poetry.lock, Syft was failing to resolve dependency edges when the dependency name used different casing than the package name.

For example, in a poetry.lock file, dj-rest-auth declares a dependency on Django (capitalized), but the actual package is listed as django (lowercase).

Per the https://packaging.python.org/en/latest/specifications/name-normalization/, package names should be treated as case-insensitive.

Root Cause

The packageRef function in the poetry dependency resolver was not normalizing package names before using them for dependency matching.

Fix

Fix: Apply the existing normalize() function to package names and extras in packageRef(), ensuring case-insensitive matching that complies with Python packaging standards.

Before: The dependency edge dj-rest-auth@7.0.1 → django@5.2.6 was missing from the SBOM dependency graph.
After: Dependency edges are correctly resolved regardless of package name casing in poetry.lock.

Some other tests have been updated that were missing this relationship previously

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Issue references
Fixes #4562

Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
name: "package name with mixed case and extra",
pkg: "Django",
extra: "argon2",
want: "django[argon2]",
Copy link
Contributor

Choose a reason for hiding this comment

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

How do the extras interact with the resolution in requires/provides?

Copy link
Contributor Author

@spiffcs spiffcs Jan 27, 2026

Choose a reason for hiding this comment

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

So here is the current behavior:

When a package requires another with extras:

  1. provides is always the base package no extras in the name
  2. then we always have the base package requirements without any extras so those resolutions can always happen
  3. If there are extras, the extra variants also get added (now run through the normalize logic)

1

// this package reference always includes the package name and no extras
provides := []string{packageRef(p.Name, "")}

2

// we always have the base package requirement without any extras to get base dependencies
requires = append(requires, packageRef(dep.Name, ""))

3

// if there are extras, we need to add a requirement for each extra individually
// for example:
// uvicorn = {version = ">=0.12.0", extras = ["standard", "else"]}
// then we must install uvicorn with the extras "standard" and "else" to satisfy the requirement
for _, extra := range dep.Extras {
// always refer to extras with the package name (e.g. name[extra])
// note: this must always be done independent of other extras (e.g. name[extra1] and name[extra2] separately
// is correct and name[extra1,extra2] will result in dependency resolution failure)
requires = append(requires, packageRef(dep.Name, extra))
}

This change does not update any of the above flow. It just makes sure that we are respecting the casing correctly in both instances of creating the provides:requires and the extras variant.

Copy link
Contributor

Choose a reason for hiding this comment

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

We reviewed this offline, and I think the behavior currently in main is correct. Provides and requires are include both a plain and a with extras variant as appropriate, like mashumaro and mashumaro[orjson], and this is unit tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No more changes needed for this PR then and we are 🟢 ❤️

@spiffcs spiffcs merged commit 9a250a4 into main Jan 27, 2026
10 checks passed
@spiffcs spiffcs deleted the 4562-poetry-bug branch January 27, 2026 20:16
@spiffcs spiffcs changed the title fix: update mixed case dependencies to have correct relationship fix: update mixed case dependencies in python to be normalized Jan 27, 2026
spiffcs added a commit to patrickpichler/syft that referenced this pull request Jan 30, 2026
* main: (114 commits)
  fix: lookup alternate scheme on url->licenseID (anchore#4588)
  chore(deps): bump the go-minor-patch group with 2 updates (anchore#4583)
  feat: add Qt6 binary detection (anchore#4550)
  chore(deps): bump the actions-minor-patch group across 1 directory with 2 updates (anchore#4584)
  fix: snap cataloger incorrectly identifies snap container as deb package (anchore#4500)
  chore(deps): update tools to latest versions (anchore#4577)
  fix: update mixed case dependencies in python to be normalized (anchore#4573)
  chore(deps): update anchore dependencies (anchore#4575)
  chore(deps): update tools to latest versions (anchore#4570)
  feat: detect Debian version from /etc/debian_version (anchore#4569)
  fix: correctly report supporting evidence for binary packages (anchore#4558)
  chore(deps): bump the actions-minor-patch group across 2 directories with 3 updates (anchore#4568)
  chore(deps): bump the go-minor-patch group with 6 updates (anchore#4567)
  chore(deps): update tools to latest versions (anchore#4565)
  chore(deps): bump github.com/spdx/tools-golang (anchore#4557)
  ci: enable zizmor to fail PRs (anchore#4556)
  Chore new slack action (anchore#4553)
  chore(deps): update anchore dependencies (anchore#4552)
  chore(deps): update tools to latest versions (anchore#4551)
  chore(deps): update tools to latest versions (anchore#4545)
  ...

Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
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.

[Bug Report] Missing some dependencies on cyclonedx formatted SBOM using syft

2 participants