mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Add Conan (C/C++) conan.lock file support (#1230)
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
This commit is contained in:
parent
e6502536a7
commit
b9b13d5525
@ -6,5 +6,5 @@ const (
|
|||||||
|
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "3.3.2"
|
JSONSchemaVersion = "4.0.0"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -28,20 +28,24 @@ can be extended to include specific package metadata struct shapes in the future
|
|||||||
// When a new package metadata definition is created it will need to be manually added here. The variable name does
|
// When a new package metadata definition is created it will need to be manually added here. The variable name does
|
||||||
// not matter as long as it is exported.
|
// not matter as long as it is exported.
|
||||||
type artifactMetadataContainer struct {
|
type artifactMetadataContainer struct {
|
||||||
Apk pkg.ApkMetadata
|
Apk pkg.ApkMetadata
|
||||||
Alpm pkg.AlpmMetadata
|
Alpm pkg.AlpmMetadata
|
||||||
Dpkg pkg.DpkgMetadata
|
Dpkg pkg.DpkgMetadata
|
||||||
Gem pkg.GemMetadata
|
Gem pkg.GemMetadata
|
||||||
Java pkg.JavaMetadata
|
Java pkg.JavaMetadata
|
||||||
Npm pkg.NpmPackageJSONMetadata
|
Npm pkg.NpmPackageJSONMetadata
|
||||||
Python pkg.PythonPackageMetadata
|
Python pkg.PythonPackageMetadata
|
||||||
Rpm pkg.RpmMetadata
|
Rpm pkg.RpmMetadata
|
||||||
Cargo pkg.CargoPackageMetadata
|
Cargo pkg.CargoPackageMetadata
|
||||||
Go pkg.GolangBinMetadata
|
Go pkg.GolangBinMetadata
|
||||||
Php pkg.PhpComposerJSONMetadata
|
Php pkg.PhpComposerJSONMetadata
|
||||||
Dart pkg.DartPubMetadata
|
Dart pkg.DartPubMetadata
|
||||||
Dotnet pkg.DotnetDepsMetadata
|
Dotnet pkg.DotnetDepsMetadata
|
||||||
Portage pkg.PortageMetadata
|
Portage pkg.PortageMetadata
|
||||||
|
Conan pkg.ConanMetadata
|
||||||
|
ConanLock pkg.ConanLockMetadata
|
||||||
|
KbPackage pkg.KbPackageMetadata
|
||||||
|
Hackage pkg.HackageMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
1574
schema/json/schema-4.0.0.json
Normal file
1574
schema/json/schema-4.0.0.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -163,12 +163,18 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.Metadata = payload
|
p.Metadata = payload
|
||||||
case pkg.ConanaMetadataType:
|
case pkg.ConanMetadataType:
|
||||||
var payload pkg.ConanMetadata
|
var payload pkg.ConanMetadata
|
||||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.Metadata = payload
|
p.Metadata = payload
|
||||||
|
case pkg.ConanLockMetadataType:
|
||||||
|
var payload pkg.ConanLockMetadata
|
||||||
|
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Metadata = payload
|
||||||
case pkg.DotnetDepsMetadataType:
|
case pkg.DotnetDepsMetadataType:
|
||||||
var payload pkg.DotnetDepsMetadata
|
var payload pkg.DotnetDepsMetadata
|
||||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||||
|
|||||||
@ -88,7 +88,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"version": "3.3.2",
|
"version": "4.0.0",
|
||||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json"
|
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-4.0.0.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -184,7 +184,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"version": "3.3.2",
|
"version": "4.0.0",
|
||||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json"
|
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-4.0.0.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,7 +111,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"version": "3.3.2",
|
"version": "4.0.0",
|
||||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json"
|
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-4.0.0.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
func NewConanfileCataloger() *common.GenericCataloger {
|
func NewConanfileCataloger() *common.GenericCataloger {
|
||||||
globParsers := map[string]common.ParserFn{
|
globParsers := map[string]common.ParserFn{
|
||||||
"**/conanfile.txt": parseConanfile,
|
"**/conanfile.txt": parseConanfile,
|
||||||
|
"**/conan.lock": parseConanlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.NewGenericCataloger(nil, globParsers, "conan-cataloger")
|
return common.NewGenericCataloger(nil, globParsers, "conan-cataloger")
|
||||||
|
|||||||
@ -40,21 +40,23 @@ func parseConanfile(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela
|
|||||||
inRequirements = false
|
inRequirements = false
|
||||||
}
|
}
|
||||||
|
|
||||||
splits := strings.Split(strings.TrimSpace(line), "/")
|
m := pkg.ConanMetadata{
|
||||||
if len(splits) < 2 || !inRequirements {
|
Ref: strings.Trim(line, "\n"),
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgName, pkgVersion := m.NameAndVersion()
|
||||||
|
|
||||||
|
if pkgName == "" || pkgVersion == "" || !inRequirements {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pkgName, pkgVersion := splits[0], splits[1]
|
|
||||||
pkgs = append(pkgs, &pkg.Package{
|
pkgs = append(pkgs, &pkg.Package{
|
||||||
Name: pkgName,
|
Name: pkgName,
|
||||||
Version: pkgVersion,
|
Version: pkgVersion,
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: m,
|
||||||
Name: pkgName,
|
|
||||||
Version: pkgVersion,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,10 +16,9 @@ func TestParseConanfile(t *testing.T) {
|
|||||||
Version: "2.13.8",
|
Version: "2.13.8",
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: pkg.ConanMetadata{
|
||||||
Name: "catch2",
|
Ref: "catch2/2.13.8",
|
||||||
Version: "2.13.8",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -27,10 +26,9 @@ func TestParseConanfile(t *testing.T) {
|
|||||||
Version: "0.6.3",
|
Version: "0.6.3",
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: pkg.ConanMetadata{
|
||||||
Name: "docopt.cpp",
|
Ref: "docopt.cpp/0.6.3",
|
||||||
Version: "0.6.3",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -38,10 +36,9 @@ func TestParseConanfile(t *testing.T) {
|
|||||||
Version: "8.1.1",
|
Version: "8.1.1",
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: pkg.ConanMetadata{
|
||||||
Name: "fmt",
|
Ref: "fmt/8.1.1",
|
||||||
Version: "8.1.1",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -49,10 +46,9 @@ func TestParseConanfile(t *testing.T) {
|
|||||||
Version: "1.9.2",
|
Version: "1.9.2",
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: pkg.ConanMetadata{
|
||||||
Name: "spdlog",
|
Ref: "spdlog/1.9.2",
|
||||||
Version: "1.9.2",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -60,10 +56,9 @@ func TestParseConanfile(t *testing.T) {
|
|||||||
Version: "2.0.20",
|
Version: "2.0.20",
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: pkg.ConanMetadata{
|
||||||
Name: "sdl",
|
Ref: "sdl/2.0.20",
|
||||||
Version: "2.0.20",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -71,10 +66,9 @@ func TestParseConanfile(t *testing.T) {
|
|||||||
Version: "1.3.8",
|
Version: "1.3.8",
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
MetadataType: pkg.ConanaMetadataType,
|
MetadataType: pkg.ConanMetadataType,
|
||||||
Metadata: pkg.ConanMetadata{
|
Metadata: pkg.ConanMetadata{
|
||||||
Name: "fltk",
|
Ref: "fltk/1.3.8",
|
||||||
Version: "1.3.8",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
82
syft/pkg/cataloger/cpp/parse_conanlock.go
Normal file
82
syft/pkg/cataloger/cpp/parse_conanlock.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package cpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// integrity check
|
||||||
|
var _ common.ParserFn = parseConanlock
|
||||||
|
|
||||||
|
type conanLock struct {
|
||||||
|
GraphLock struct {
|
||||||
|
Nodes map[string]struct {
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
PackageID string `json:"package_id"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
Prev string `json:"prev"`
|
||||||
|
Requires string `json:"requires"`
|
||||||
|
BuildRequires string `json:"build_requires"`
|
||||||
|
PythonRequires string `json:"py_requires"`
|
||||||
|
Options string `json:"options"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
} `json:"nodes"`
|
||||||
|
} `json:"graph_lock"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
ProfileHost string `json:"profile_host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseConanlock is a parser function for conan.lock contents, returning all packages discovered.
|
||||||
|
func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||||
|
pkgs := []*pkg.Package{}
|
||||||
|
var cl conanLock
|
||||||
|
if err := json.NewDecoder(reader).Decode(&cl); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
for _, node := range cl.GraphLock.Nodes {
|
||||||
|
metadata := pkg.ConanLockMetadata{
|
||||||
|
Ref: node.Ref,
|
||||||
|
Options: parseOptions(node.Options),
|
||||||
|
Path: node.Path,
|
||||||
|
Context: node.Context,
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgName, pkgVersion := metadata.NameAndVersion()
|
||||||
|
if pkgName == "" || pkgVersion == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgs = append(pkgs, &pkg.Package{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
Language: pkg.CPP,
|
||||||
|
Type: pkg.ConanPkg,
|
||||||
|
MetadataType: pkg.ConanLockMetadataType,
|
||||||
|
Metadata: metadata,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOptions(options string) map[string]string {
|
||||||
|
o := make(map[string]string)
|
||||||
|
if len(options) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
kvps := strings.Split(options, "\n")
|
||||||
|
for _, kvp := range kvps {
|
||||||
|
kv := strings.Split(kvp, "=")
|
||||||
|
if len(kv) == 2 {
|
||||||
|
o[kv[0]] = kv[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
47
syft/pkg/cataloger/cpp/parse_conanlock_test.go
Normal file
47
syft/pkg/cataloger/cpp/parse_conanlock_test.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package cpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-test/deep"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseConanlock(t *testing.T) {
|
||||||
|
expected := []*pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "zlib",
|
||||||
|
Version: "1.2.12",
|
||||||
|
Language: pkg.CPP,
|
||||||
|
Type: pkg.ConanPkg,
|
||||||
|
MetadataType: pkg.ConanLockMetadataType,
|
||||||
|
Metadata: pkg.ConanLockMetadata{
|
||||||
|
Ref: "zlib/1.2.12",
|
||||||
|
Options: map[string]string{
|
||||||
|
"fPIC": "True",
|
||||||
|
"shared": "False",
|
||||||
|
},
|
||||||
|
Path: "all/conanfile.py",
|
||||||
|
Context: "host",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture, err := os.Open("test-fixtures/conan.lock")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no relationships are under test yet
|
||||||
|
actual, _, err := parseConanlock(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
syft/pkg/cataloger/cpp/test-fixtures/conan.lock
Normal file
15
syft/pkg/cataloger/cpp/test-fixtures/conan.lock
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"graph_lock": {
|
||||||
|
"nodes": {
|
||||||
|
"0": {
|
||||||
|
"ref": "zlib/1.2.12",
|
||||||
|
"options": "fPIC=True\nshared=False",
|
||||||
|
"path": "all/conanfile.py",
|
||||||
|
"context": "host"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revisions_enabled": false
|
||||||
|
},
|
||||||
|
"version": "0.4",
|
||||||
|
"profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=9\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n"
|
||||||
|
}
|
||||||
50
syft/pkg/conan_lock_metadata.go
Normal file
50
syft/pkg/conan_lock_metadata.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/linux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConanLockMetadata struct {
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
PackageID string `json:"package_id,omitempty"`
|
||||||
|
Prev string `json:"prev,omitempty"`
|
||||||
|
Requires string `json:"requires,omitempty"`
|
||||||
|
BuildRequires string `json:"build_requires,omitempty"`
|
||||||
|
PythonRequires string `json:"py_requires,omitempty"`
|
||||||
|
Options map[string]string `json:"options,omitempty"`
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
Context string `json:"context,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ConanLockMetadata) PackageURL(_ *linux.Release) string {
|
||||||
|
var qualifiers packageurl.Qualifiers
|
||||||
|
|
||||||
|
name, version := m.NameAndVersion()
|
||||||
|
|
||||||
|
return packageurl.NewPackageURL(
|
||||||
|
packageurl.TypeConan,
|
||||||
|
"",
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
qualifiers,
|
||||||
|
"",
|
||||||
|
).ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NameAndVersion returns the name and version of the package.
|
||||||
|
// If ref is not in the format of "name/version@user/channel", then an empty string is returned for both.
|
||||||
|
func (m ConanLockMetadata) NameAndVersion() (name, version string) {
|
||||||
|
if len(m.Ref) < 1 {
|
||||||
|
return name, version
|
||||||
|
}
|
||||||
|
|
||||||
|
splits := strings.Split(strings.Split(m.Ref, "@")[0], "/")
|
||||||
|
if len(splits) < 2 {
|
||||||
|
return name, version
|
||||||
|
}
|
||||||
|
|
||||||
|
return splits[0], splits[1]
|
||||||
|
}
|
||||||
27
syft/pkg/conan_lock_metadata_test.go
Normal file
27
syft/pkg/conan_lock_metadata_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestConanLockMetadata_PackageURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
m ConanLockMetadata
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "happy path",
|
||||||
|
m: ConanLockMetadata{
|
||||||
|
Ref: "farmerbrown5/3.13.9",
|
||||||
|
},
|
||||||
|
want: "pkg:conan/farmerbrown5@3.13.9",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
if got := test.m.PackageURL(nil); got != test.want {
|
||||||
|
t.Errorf("ConanMetadata.PackageURL() = %v, want %v", got, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,24 +1,44 @@
|
|||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/anchore/packageurl-go"
|
"github.com/anchore/packageurl-go"
|
||||||
"github.com/anchore/syft/syft/linux"
|
"github.com/anchore/syft/syft/linux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConanMetadata struct {
|
type ConanMetadata struct {
|
||||||
Name string `mapstructure:"name" json:"name"`
|
Ref string `mapstructure:"ref" json:"ref"`
|
||||||
Version string `mapstructure:"version" json:"version"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ConanMetadata) PackageURL(_ *linux.Release) string {
|
func (m ConanMetadata) PackageURL(_ *linux.Release) string {
|
||||||
var qualifiers packageurl.Qualifiers
|
var qualifiers packageurl.Qualifiers
|
||||||
|
|
||||||
|
name, version := m.NameAndVersion()
|
||||||
|
|
||||||
return packageurl.NewPackageURL(
|
return packageurl.NewPackageURL(
|
||||||
packageurl.TypeConan,
|
packageurl.TypeConan,
|
||||||
"",
|
"",
|
||||||
m.Name,
|
name,
|
||||||
m.Version,
|
version,
|
||||||
qualifiers,
|
qualifiers,
|
||||||
"",
|
"",
|
||||||
).ToString()
|
).ToString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NameAndVersion tries to return the name and version of a cpp package
|
||||||
|
// given the ref format: pkg/version
|
||||||
|
// it returns empty strings if ref is empty or parsing is unsuccessful
|
||||||
|
func (m ConanMetadata) NameAndVersion() (name, version string) {
|
||||||
|
if len(m.Ref) < 1 {
|
||||||
|
return name, version
|
||||||
|
}
|
||||||
|
|
||||||
|
splits := strings.Split(strings.TrimSpace(m.Ref), "/")
|
||||||
|
|
||||||
|
if len(splits) < 2 {
|
||||||
|
return name, version
|
||||||
|
}
|
||||||
|
|
||||||
|
return splits[0], splits[1]
|
||||||
|
}
|
||||||
|
|||||||
27
syft/pkg/conan_metadata_test.go
Normal file
27
syft/pkg/conan_metadata_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestConanMetadata_PackageURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
m ConanMetadata
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "happy path",
|
||||||
|
m: ConanMetadata{
|
||||||
|
Ref: "catch2/2.13.8",
|
||||||
|
},
|
||||||
|
want: "pkg:conan/catch2@2.13.8",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
if got := test.m.PackageURL(nil); got != test.want {
|
||||||
|
t.Errorf("ConanMetadata.PackageURL() = %v, want %v", got, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,7 +26,8 @@ const (
|
|||||||
GolangBinMetadataType MetadataType = "GolangBinMetadata"
|
GolangBinMetadataType MetadataType = "GolangBinMetadata"
|
||||||
PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata"
|
PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata"
|
||||||
CocoapodsMetadataType MetadataType = "CocoapodsMetadataType"
|
CocoapodsMetadataType MetadataType = "CocoapodsMetadataType"
|
||||||
ConanaMetadataType MetadataType = "ConanaMetadataType"
|
ConanMetadataType MetadataType = "ConanMetadataType"
|
||||||
|
ConanLockMetadataType MetadataType = "ConanLockMetadataType"
|
||||||
PortageMetadataType MetadataType = "PortageMetadata"
|
PortageMetadataType MetadataType = "PortageMetadata"
|
||||||
HackageMetadataType MetadataType = "HackageMetadataType"
|
HackageMetadataType MetadataType = "HackageMetadataType"
|
||||||
)
|
)
|
||||||
@ -47,7 +48,8 @@ var AllMetadataTypes = []MetadataType{
|
|||||||
GolangBinMetadataType,
|
GolangBinMetadataType,
|
||||||
PhpComposerJSONMetadataType,
|
PhpComposerJSONMetadataType,
|
||||||
CocoapodsMetadataType,
|
CocoapodsMetadataType,
|
||||||
ConanaMetadataType,
|
ConanMetadataType,
|
||||||
|
ConanLockMetadataType,
|
||||||
PortageMetadataType,
|
PortageMetadataType,
|
||||||
HackageMetadataType,
|
HackageMetadataType,
|
||||||
}
|
}
|
||||||
@ -68,7 +70,8 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
|||||||
GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}),
|
GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}),
|
||||||
PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}),
|
PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}),
|
||||||
CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}),
|
CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}),
|
||||||
ConanaMetadataType: reflect.TypeOf(ConanMetadata{}),
|
ConanMetadataType: reflect.TypeOf(ConanMetadata{}),
|
||||||
|
ConanLockMetadataType: reflect.TypeOf(ConanLockMetadata{}),
|
||||||
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
||||||
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -239,14 +239,29 @@ func TestPackageURL(t *testing.T) {
|
|||||||
Version: "2.13.8",
|
Version: "2.13.8",
|
||||||
Type: ConanPkg,
|
Type: ConanPkg,
|
||||||
Language: CPP,
|
Language: CPP,
|
||||||
MetadataType: ConanaMetadataType,
|
MetadataType: ConanMetadataType,
|
||||||
Metadata: ConanMetadata{
|
Metadata: ConanMetadata{
|
||||||
Name: "catch2",
|
Ref: "catch2/2.13.8",
|
||||||
Version: "2.13.8",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "pkg:conan/catch2@2.13.8",
|
expected: "pkg:conan/catch2@2.13.8",
|
||||||
},
|
},
|
||||||
|
// note both Ref should parse the same for conan ecosystem
|
||||||
|
{
|
||||||
|
name: "conan lock",
|
||||||
|
pkg: Package{
|
||||||
|
Name: "catch2",
|
||||||
|
Version: "2.13.8",
|
||||||
|
Type: ConanPkg,
|
||||||
|
Language: CPP,
|
||||||
|
MetadataType: ConanLockMetadataType,
|
||||||
|
Metadata: ConanLockMetadata{
|
||||||
|
Ref: "catch2/2.13.8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "pkg:conan/catch2@2.13.8",
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hackage",
|
name: "hackage",
|
||||||
pkg: Package{
|
pkg: Package{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user