diff --git a/pkg/dependency/parser/python/poetry/parse.go b/pkg/dependency/parser/python/poetry/parse.go index e691a0cb2532..8b06942d3b6b 100644 --- a/pkg/dependency/parser/python/poetry/parse.go +++ b/pkg/dependency/parser/python/poetry/parse.go @@ -105,7 +105,7 @@ func (p *Parser) parseDependencies(deps map[string]any, pkgVersions map[string][ } func (p *Parser) parseDependency(name string, versRange any, pkgVersions map[string][]string) (string, error) { - name = normalizePkgName(name) + name = NormalizePkgName(name) vers, ok := pkgVersions[name] if !ok { return "", xerrors.Errorf("no version found for %q", name) @@ -149,9 +149,11 @@ func matchVersion(currentVersion, constraint string) (bool, error) { return c.Check(v), nil } -func normalizePkgName(name string) string { +// NormalizePkgName normalizes the package name based on pep-0426 +func NormalizePkgName(name string) string { // The package names don't use `_`, `.` or upper case, but dependency names can contain them. // We need to normalize those names. + // cf. https://peps.python.org/pep-0426/#name name = strings.ToLower(name) // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L819 name = strings.ReplaceAll(name, "_", "-") // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L50 name = strings.ReplaceAll(name, ".", "-") // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L816 diff --git a/pkg/fanal/analyzer/language/python/poetry/poetry.go b/pkg/fanal/analyzer/language/python/poetry/poetry.go index cab008e4bd93..b16ba88481c5 100644 --- a/pkg/fanal/analyzer/language/python/poetry/poetry.go +++ b/pkg/fanal/analyzer/language/python/poetry/poetry.go @@ -7,7 +7,6 @@ import ( "io/fs" "os" "path/filepath" - "strings" "github.com/samber/lo" "golang.org/x/xerrors" @@ -104,18 +103,9 @@ func (a poetryAnalyzer) mergePyProject(fsys fs.FS, dir string, app *types.Applic return xerrors.Errorf("unable to parse %s: %w", path, err) } - // Convert package name to lower case - p = lo.MapKeys(p, func(_ any, key string) string { - return strings.ToLower(key) - }) // Identify the direct/transitive dependencies for i, pkg := range app.Packages { - // There are cases where package names from `poetry.lock` and `pyproject.toml` use different case. - // e.g. `pyproject.toml` uses `Flask`, but `poetry.lock` uses `flask` - // cf. https://github.com/aquasecurity/trivy/issues/6817 - // So we need to compare lowercase package names. - pkgName := strings.ToLower(pkg.Name) - if _, ok := p[pkgName]; ok { + if _, ok := p[pkg.Name]; ok { app.Packages[i].Relationship = types.RelationshipDirect } else { app.Packages[i].Indirect = true @@ -138,5 +128,11 @@ func (a poetryAnalyzer) parsePyProject(fsys fs.FS, path string) (map[string]any, if err != nil { return nil, err } + + // Packages from `pyproject.toml` can use uppercase characters, `.` and `_`. + parsed = lo.MapKeys(parsed, func(_ any, pkgName string) string { + return poetry.NormalizePkgName(pkgName) + }) + return parsed, nil }