Skip to content

Commit 86baeeb

Browse files
authored
fix(rust): omit Cargo PURLs for local packages (#5105)
Signed-off-by: Enes Deniz <142517728+3nesdeniz@users.noreply.github.com>
1 parent 2dcf516 commit 86baeeb

4 files changed

Lines changed: 139 additions & 2 deletions

File tree

syft/pkg/cataloger/rust/package.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func newPackageFromCargoMetadata(m pkg.RustCargoLockEntry, locations ...file.Loc
1414
Name: m.Name,
1515
Version: m.Version,
1616
Locations: file.NewLocationSet(locations...),
17-
PURL: packageURL(m.Name, m.Version),
17+
PURL: cargoLockPackageURL(m),
1818
Language: pkg.Rust,
1919
Type: pkg.RustPkg,
2020
Metadata: m,
@@ -25,6 +25,18 @@ func newPackageFromCargoMetadata(m pkg.RustCargoLockEntry, locations ...file.Loc
2525
return p
2626
}
2727

28+
func cargoLockPackageURL(m pkg.RustCargoLockEntry) string {
29+
// Cargo omits source for packages resolved from the local workspace or a
30+
// path dependency. A cargo PURL without a repository qualifier identifies
31+
// a package on crates.io, so emitting one for a local package can cause
32+
// downstream scanners to match unrelated registry vulnerabilities.
33+
if m.Source == "" {
34+
return ""
35+
}
36+
37+
return packageURL(m.Name, m.Version)
38+
}
39+
2840
func newPackageFromAudit(dep *rustaudit.Package, locations ...file.Location) pkg.Package {
2941
p := pkg.Package{
3042
Name: dep.Name,

syft/pkg/cataloger/rust/package_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"testing"
55

66
"github.com/stretchr/testify/assert"
7+
8+
"github.com/anchore/syft/syft/pkg"
79
)
810

911
func Test_packageURL(t *testing.T) {
@@ -31,3 +33,34 @@ func Test_packageURL(t *testing.T) {
3133
})
3234
}
3335
}
36+
37+
func TestNewPackageFromCargoMetadataPURL(t *testing.T) {
38+
tests := []struct {
39+
name string
40+
source string
41+
want string
42+
}{
43+
{
44+
name: "crates.io package",
45+
source: "registry+https://github.com/rust-lang/crates.io-index",
46+
want: "pkg:cargo/telemetry@0.1.0",
47+
},
48+
{
49+
name: "local path package",
50+
source: "",
51+
want: "",
52+
},
53+
}
54+
55+
for _, tt := range tests {
56+
t.Run(tt.name, func(t *testing.T) {
57+
got := newPackageFromCargoMetadata(pkg.RustCargoLockEntry{
58+
Name: "telemetry",
59+
Version: "0.1.0",
60+
Source: tt.source,
61+
})
62+
63+
assert.Equal(t, tt.want, got.PURL)
64+
})
65+
}
66+
}

syft/pkg/cataloger/rust/parse_cargo_lock_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ func TestCargoLockWithGitDependencies(t *testing.T) {
351351
helloWorld := pkg.Package{
352352
Name: "hello_world",
353353
Version: "0.1.0",
354-
PURL: "pkg:cargo/hello_world@0.1.0",
354+
PURL: "",
355355
Locations: locations,
356356
Language: pkg.Rust,
357357
Type: pkg.RustPkg,
@@ -673,6 +673,77 @@ func TestCargoLockWithGitDependencies(t *testing.T) {
673673
pkgtest.TestFileParser(t, fixture, parseCargoLock, expectedPkgs, expectedRelationships)
674674
}
675675

676+
func TestCargoLockWithPathDependencies(t *testing.T) {
677+
fixture := "testdata/path-deps/Cargo.lock"
678+
locations := file.NewLocationSet(file.NewLocation(fixture))
679+
680+
app := pkg.Package{
681+
Name: "app",
682+
Version: "1.0.0",
683+
Locations: locations,
684+
Language: pkg.Rust,
685+
Type: pkg.RustPkg,
686+
Licenses: pkg.NewLicenseSet(),
687+
Metadata: pkg.RustCargoLockEntry{
688+
Name: "app",
689+
Version: "1.0.0",
690+
Dependencies: []string{
691+
"memchr",
692+
"telemetry",
693+
},
694+
},
695+
}
696+
memchr := pkg.Package{
697+
Name: "memchr",
698+
Version: "2.7.4",
699+
PURL: "pkg:cargo/memchr@2.7.4",
700+
Locations: locations,
701+
Language: pkg.Rust,
702+
Type: pkg.RustPkg,
703+
Licenses: pkg.NewLicenseSet(),
704+
Metadata: pkg.RustCargoLockEntry{
705+
Name: "memchr",
706+
Version: "2.7.4",
707+
Source: "registry+https://github.com/rust-lang/crates.io-index",
708+
Checksum: "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3",
709+
Dependencies: []string{},
710+
},
711+
}
712+
telemetry := pkg.Package{
713+
Name: "telemetry",
714+
Version: "0.1.0",
715+
Locations: locations,
716+
Language: pkg.Rust,
717+
Type: pkg.RustPkg,
718+
Licenses: pkg.NewLicenseSet(),
719+
Metadata: pkg.RustCargoLockEntry{
720+
Name: "telemetry",
721+
Version: "0.1.0",
722+
Dependencies: []string{},
723+
},
724+
}
725+
726+
expectedPkgs := []pkg.Package{
727+
app,
728+
memchr,
729+
telemetry,
730+
}
731+
expectedRelationships := []artifact.Relationship{
732+
{
733+
From: memchr,
734+
To: app,
735+
Type: artifact.DependencyOfRelationship,
736+
},
737+
{
738+
From: telemetry,
739+
To: app,
740+
Type: artifact.DependencyOfRelationship,
741+
},
742+
}
743+
744+
pkgtest.TestFileParser(t, fixture, parseCargoLock, expectedPkgs, expectedRelationships)
745+
}
746+
676747
func TestCargoLockDependencySpecification(t *testing.T) {
677748
tests := []struct {
678749
name string

syft/pkg/cataloger/rust/testdata/path-deps/Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)