fix uv.lock Parser Graph Root Handling (#397)

* fix uv.lock Parser Graph Root Handling

* fixed test case for pathToRoot

* added support for dev dependencies & extra support fot scanning root pkg

---------

Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
This commit is contained in:
Sahil Bansal 2025-03-20 10:31:55 +05:30 committed by GitHub
parent ec141c3693
commit 5387a395a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 42 deletions

View File

@ -7,7 +7,6 @@ import (
"strings"
"github.com/BurntSushi/toml"
"github.com/safedep/dry/semver"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/models"
)
@ -17,7 +16,8 @@ type uvLockPackage struct {
Version string `toml:"version"`
Source uvLockPackageSource `toml:"source"`
Dependencies []uvDependency `toml:"dependencies"`
Groups map[string][]uvDependency `toml:"optional-dependencies"`
OptionalDependencies map[string][]uvDependency `toml:"optional-dependencies"`
DevDependencies map[string][]uvDependency `toml:"dev-dependencies"`
Metadata Metadata `toml:"metadata"`
}
@ -26,6 +26,8 @@ type uvLockPackageSource struct {
URL string `toml:"url"`
Subdir string `toml:"subdir,omitempty"`
Ref string `toml:"ref,omitempty"`
Virtual string `toml:"virtual,omitempty"`
Editable string `toml:"editable,omitempty"`
}
type uvDependency struct {
@ -71,9 +73,9 @@ func parseUvPackageLockAsGraph(lockfilePath string, config *ParserConfig) (*mode
defer func() {
for _, pkg := range parsedLockFile.Packages {
if len(pkg.Metadata.RequiresDist) != 0 {
for _, dep := range pkg.Metadata.RequiresDist {
node := uvGraphFindByVersionRange(dependencyGraph, dep.Name, dep.Specifier)
if pkg.Source.Virtual != "" || pkg.Source.Editable != "" {
for _, dep := range pkg.Dependencies {
node := uvFindPackageByName(dependencyGraph, dep.Name)
if node != nil {
node.SetRoot(true)
}
@ -89,14 +91,26 @@ func parseUvPackageLockAsGraph(lockfilePath string, config *ParserConfig) (*mode
Manifest: manifest,
}
if pkgInfo.Source.Virtual == "" || pkgInfo.Source.Editable == "" {
dependencyGraph.AddNode(pkg)
}
for _, depName := range pkgInfo.Dependencies {
defer uvGraphAddDependencyRelation(dependencyGraph, pkg, depName.Name)
}
for groupName, deps := range pkgInfo.Groups {
if !config.IncludeDevDependencies && isDevGroup(groupName) {
for _, deps := range pkgInfo.OptionalDependencies {
if !config.IncludeDevDependencies {
continue
}
for _, depName := range deps {
defer uvGraphAddDependencyRelation(dependencyGraph, pkg, depName.Name)
}
}
for _, deps := range pkgInfo.DevDependencies {
if !config.IncludeDevDependencies {
continue
}
@ -128,27 +142,3 @@ func uvFindPackageByName(graph *models.DependencyGraph[*models.Package], name st
}
return nil
}
func isDevGroup(groupName string) bool {
return strings.Contains(strings.ToLower(groupName), "dev")
}
func uvGraphFindByVersionRange(graph *models.DependencyGraph[*models.Package],
name string, versionRange string,
) *models.DependencyGraphNode[*models.Package] {
for _, node := range graph.GetNodes() {
if !strings.EqualFold(node.Data.GetName(), name) {
continue
}
if node.Data.GetVersion() == versionRange {
return node
}
if semver.IsVersionInRange(node.Data.GetVersion(), versionRange) {
return node
}
}
return nil
}

View File

@ -86,7 +86,7 @@ func TestUvGraphParserPathToRoot(t *testing.T) {
assert.NotNil(t, asgirefNode)
pathToRoot := pm.DependencyGraph.PathToRoot(asgirefNode)
assert.Equal(t, 3, len(pathToRoot))
assert.Equal(t, 2, len(pathToRoot))
assert.Equal(t, "asgiref", pathToRoot[0].GetName())
assert.Equal(t, "django", pathToRoot[1].GetName())
}