mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 10:36:45 +01:00
add cataloger for rust crates from Cargo.lock files
Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
This commit is contained in:
parent
a83d79f330
commit
ba81bfe529
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/cataloger/python"
|
"github.com/anchore/syft/syft/cataloger/python"
|
||||||
"github.com/anchore/syft/syft/cataloger/rpmdb"
|
"github.com/anchore/syft/syft/cataloger/rpmdb"
|
||||||
"github.com/anchore/syft/syft/cataloger/ruby"
|
"github.com/anchore/syft/syft/cataloger/ruby"
|
||||||
|
"github.com/anchore/syft/syft/cataloger/rust"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
@ -39,6 +40,7 @@ func ImageCatalogers() []Cataloger {
|
|||||||
java.NewJavaCataloger(),
|
java.NewJavaCataloger(),
|
||||||
apkdb.NewApkdbCataloger(),
|
apkdb.NewApkdbCataloger(),
|
||||||
golang.NewGoModCataloger(),
|
golang.NewGoModCataloger(),
|
||||||
|
rust.NewCargoLockCataloger(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,5 +56,6 @@ func DirectoryCatalogers() []Cataloger {
|
|||||||
java.NewJavaCataloger(),
|
java.NewJavaCataloger(),
|
||||||
apkdb.NewApkdbCataloger(),
|
apkdb.NewApkdbCataloger(),
|
||||||
golang.NewGoModCataloger(),
|
golang.NewGoModCataloger(),
|
||||||
|
rust.NewCargoLockCataloger(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,6 +115,14 @@ func TestPackageURL(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expected: "pkg:deb/name@v0.1.0",
|
expected: "pkg:deb/name@v0.1.0",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pkg: pkg.Package{
|
||||||
|
Name: "name",
|
||||||
|
Version: "v0.1.0",
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
},
|
||||||
|
expected: "pkg:cargo/name@v0.1.0",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|||||||
18
syft/cataloger/rust/cargo_metadata.go
Normal file
18
syft/cataloger/rust/cargo_metadata.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package rust
|
||||||
|
|
||||||
|
import "github.com/anchore/syft/syft/pkg"
|
||||||
|
|
||||||
|
type CargoMetadata struct {
|
||||||
|
Packages []CargoMetadataPackage `toml:"package"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pkgs returns all of the packages referenced within the Cargo.lock metadata.
|
||||||
|
func (m CargoMetadata) Pkgs() []pkg.Package {
|
||||||
|
pkgs := make([]pkg.Package, 0)
|
||||||
|
|
||||||
|
for _, p := range m.Packages {
|
||||||
|
pkgs = append(pkgs, p.Pkg())
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs
|
||||||
|
}
|
||||||
21
syft/cataloger/rust/cargo_metadata_package.go
Normal file
21
syft/cataloger/rust/cargo_metadata_package.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package rust
|
||||||
|
|
||||||
|
import "github.com/anchore/syft/syft/pkg"
|
||||||
|
|
||||||
|
type CargoMetadataPackage struct {
|
||||||
|
Name string `toml:"name"`
|
||||||
|
Version string `toml:"version"`
|
||||||
|
Source string `toml:"source"`
|
||||||
|
Checksum string `toml:"checksum"`
|
||||||
|
Dependencies []string `toml:"dependencies"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pkg returns the standard `pkg.Package` representation of the package referenced within the Cargo.lock metadata.
|
||||||
|
func (p CargoMetadataPackage) Pkg() pkg.Package {
|
||||||
|
return pkg.Package{
|
||||||
|
Name: p.Name,
|
||||||
|
Version: p.Version,
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
}
|
||||||
|
}
|
||||||
17
syft/cataloger/rust/cataloger.go
Normal file
17
syft/cataloger/rust/cataloger.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Package rust provides a concrete Cataloger implementation for Cargo.lock files.
|
||||||
|
*/
|
||||||
|
package rust
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/cataloger/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCargoLockCataloger returns a new Rust Cargo lock file cataloger object.
|
||||||
|
func NewCargoLockCataloger() *common.GenericCataloger {
|
||||||
|
globParsers := map[string]common.ParserFn{
|
||||||
|
"**/Cargo.lock": parseCargoLock,
|
||||||
|
}
|
||||||
|
|
||||||
|
return common.NewGenericCataloger(nil, globParsers, "rust-cataloger")
|
||||||
|
}
|
||||||
29
syft/cataloger/rust/parse_cargo_lock.go
Normal file
29
syft/cataloger/rust/parse_cargo_lock.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package rust
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/cataloger/common"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/pelletier/go-toml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// integrity check
|
||||||
|
var _ common.ParserFn = parseCargoLock
|
||||||
|
|
||||||
|
// parseCargoLock is a parser function for Cargo.lock contents, returning all rust cargo crates discovered.
|
||||||
|
func parseCargoLock(_ string, reader io.Reader) ([]pkg.Package, error) {
|
||||||
|
tree, err := toml.LoadReader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to load Cargo.lock for parsing: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata := CargoMetadata{}
|
||||||
|
err = tree.Unmarshal(&metadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to parse Cargo.lock: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata.Pkgs(), nil
|
||||||
|
}
|
||||||
99
syft/cataloger/rust/parse_cargo_lock_test.go
Normal file
99
syft/cataloger/rust/parse_cargo_lock_test.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package rust
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/go-test/deep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseCargoLock(t *testing.T) {
|
||||||
|
expected := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "ansi_term",
|
||||||
|
Version: "0.12.1",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "matches",
|
||||||
|
Version: "0.1.8",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "memchr",
|
||||||
|
Version: "2.3.3",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "natord",
|
||||||
|
Version: "1.0.9",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "nom",
|
||||||
|
Version: "4.2.3",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "unicode-bidi",
|
||||||
|
Version: "0.3.4",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "version_check",
|
||||||
|
Version: "0.1.5",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "winapi",
|
||||||
|
Version: "0.3.9",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "winapi-i686-pc-windows-gnu",
|
||||||
|
Version: "0.4.0",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "winapi-x86_64-pc-windows-gnu",
|
||||||
|
Version: "0.4.0",
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Licenses: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture, err := os.Open("test-fixtures/Cargo.lock")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := parseCargoLock(fixture.Name(), fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
differences := deep.Equal(expected, actual)
|
||||||
|
if differences != nil {
|
||||||
|
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||||
|
}
|
||||||
|
}
|
||||||
76
syft/cataloger/rust/test-fixtures/Cargo.lock
generated
Normal file
76
syft/cataloger/rust/test-fixtures/Cargo.lock
generated
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matches"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "natord"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "4.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||||
|
dependencies = [
|
||||||
|
"matches",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
@ -11,6 +11,7 @@ const (
|
|||||||
Python Language = "python"
|
Python Language = "python"
|
||||||
Ruby Language = "ruby"
|
Ruby Language = "ruby"
|
||||||
Go Language = "go"
|
Go Language = "go"
|
||||||
|
Rust Language = "rust"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllLanguages is a set of all programming languages detected by syft.
|
// AllLanguages is a set of all programming languages detected by syft.
|
||||||
@ -20,6 +21,7 @@ var AllLanguages = []Language{
|
|||||||
Python,
|
Python,
|
||||||
Ruby,
|
Ruby,
|
||||||
Go,
|
Go,
|
||||||
|
Rust,
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the language.
|
// String returns the string representation of the language.
|
||||||
|
|||||||
@ -13,4 +13,5 @@ const (
|
|||||||
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
|
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
|
||||||
RpmdbMetadataType MetadataType = "RpmdbMetadata"
|
RpmdbMetadataType MetadataType = "RpmdbMetadata"
|
||||||
PythonPackageMetadataType MetadataType = "PythonPackageMetadata"
|
PythonPackageMetadataType MetadataType = "PythonPackageMetadata"
|
||||||
|
RustCrateMetadataType MetadataType = "RustCrateMetadata"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -17,6 +17,7 @@ const (
|
|||||||
JavaPkg Type = "java-archive"
|
JavaPkg Type = "java-archive"
|
||||||
JenkinsPluginPkg Type = "jenkins-plugin"
|
JenkinsPluginPkg Type = "jenkins-plugin"
|
||||||
GoModulePkg Type = "go-module"
|
GoModulePkg Type = "go-module"
|
||||||
|
RustPkg Type = "rust-crate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllPkgs represents all supported package types
|
// AllPkgs represents all supported package types
|
||||||
@ -30,6 +31,7 @@ var AllPkgs = []Type{
|
|||||||
JavaPkg,
|
JavaPkg,
|
||||||
JenkinsPluginPkg,
|
JenkinsPluginPkg,
|
||||||
GoModulePkg,
|
GoModulePkg,
|
||||||
|
RustPkg,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackageURLType returns the PURL package type for the current package.
|
// PackageURLType returns the PURL package type for the current package.
|
||||||
@ -51,6 +53,8 @@ func (t Type) PackageURLType() string {
|
|||||||
return packageurl.TypeRPM
|
return packageurl.TypeRPM
|
||||||
case GoModulePkg:
|
case GoModulePkg:
|
||||||
return packageurl.TypeGolang
|
return packageurl.TypeGolang
|
||||||
|
case RustPkg:
|
||||||
|
return "cargo"
|
||||||
default:
|
default:
|
||||||
// TODO: should this be a "generic" purl type instead?
|
// TODO: should this be a "generic" purl type instead?
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@ -184,4 +184,14 @@ var commonTestCases = []testCase{
|
|||||||
"github.com/bmatcuk/doublestar": "v1.3.1",
|
"github.com/bmatcuk/doublestar": "v1.3.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "find rust crates",
|
||||||
|
pkgType: pkg.RustPkg,
|
||||||
|
pkgLanguage: pkg.Rust,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"memchr": "2.3.3",
|
||||||
|
"nom": "4.2.3",
|
||||||
|
"version_check": "0.1.5",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
25
test/integration/test-fixtures/image-pkg-coverage/rust/Cargo.lock
generated
Normal file
25
test/integration/test-fixtures/image-pkg-coverage/rust/Cargo.lock
generated
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "4.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user