Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix order of rust dependencies and support git sources in Cargo.lock dependencies #3502

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 37 additions & 29 deletions syft/pkg/cataloger/rust/parse_cargo_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package rust
import (
"context"
"fmt"
"strings"

"github.com/pelletier/go-toml"

"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/unknown"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/pkg/cataloger/internal/dependency"
)

var _ generic.Parser = parseCargoLock
Expand All @@ -33,7 +36,6 @@ func parseCargoLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
}

var pkgs []pkg.Package
pkgIndex := make(map[string]int)

for _, p := range m.Packages {
if p.Dependencies == nil {
Expand All @@ -47,36 +49,42 @@ func parseCargoLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
pkgs,
newPkg,
)
newIx := len(pkgs) - 1
// Cargo.lock dependencies are strings that are the name of a package, if that
// is unambiguous, or a string like "name version" if the name alone is not
// ambiguous. Set both keys in the map, since we don't know which key is
// going to be used until we're trying to resolve dependencies. If the
// first key is overwritten, that means the package name was an ambiguous dependency
// and "name version" will be used as the key anyway.
keys := []string{
newPkg.Name,
fmt.Sprintf("%s %s", newPkg.Name, newPkg.Version),
}
for _, k := range keys {
pkgIndex[k] = newIx
}
}
var relationships []artifact.Relationship
for _, p := range pkgs {
meta := p.Metadata.(pkg.RustCargoLockEntry)
for _, d := range meta.Dependencies {
i, ok := pkgIndex[d]
if !ok {
continue
}
relationships = append(relationships, artifact.Relationship{
From: p,
To: pkgs[i],
Type: artifact.DependencyOfRelationship,
})

return pkgs, dependency.Resolve(dependencySpecification, pkgs), unknown.IfEmptyf(pkgs, "unable to determine packages")
}

func dependencySpecification(p pkg.Package) dependency.Specification {
rustMeta, ok := p.Metadata.(pkg.RustCargoLockEntry)
if !ok {
log.Tracef("cataloger failed to extract rust Cargo.lock metadata for package %+v", p.Name)
return dependency.Specification{}
}

// Cargo.lock dependencies are strings that are the name of a package, if that
// is unambiguous, or a string like "name version" if the name alone is not
// ambiguous, or strings like "name version (source)" if "name version" is ambiguous.
// Provide all the strings, since we don't know which string will be used.
// In other words, each package "provides" 3 entries, one for each name format,
// and each package "requires" whatever it actually requires based on the Cargo.lock.
provides := []string{
p.Name,
fmt.Sprintf("%s %s", p.Name, p.Version),
}

if rustMeta.Source != "" {
src := rustMeta.Source
if strings.HasPrefix(src, "git") && strings.Contains(src, "#") {
src = strings.Split(src, "#")[0]
}

provides = append(provides, fmt.Sprintf("%s %s (%s)", p.Name, p.Version, src))
}

return pkgs, relationships, unknown.IfEmptyf(pkgs, "unable to determine packages")
return dependency.Specification{
ProvidesRequires: dependency.ProvidesRequires{
Provides: provides,
Requires: rustMeta.Dependencies,
},
}
}
Loading
Loading