From 67d8f250bd1da30455b522599780ff2f38d8e947 Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Wed, 28 Sep 2022 11:00:51 +0900 Subject: [PATCH 01/12] [CPP] add Conan conan.lock file support Signed-off-by: Hiroaki KAWAI --- syft/pkg/cataloger/cpp/cataloger.go | 1 + syft/pkg/cataloger/cpp/parse_conanlock.go | 52 +++++++++++++++++++ .../pkg/cataloger/cpp/parse_conanlock_test.go | 42 +++++++++++++++ .../cataloger/cpp/test-fixtures/conan.lock | 15 ++++++ 4 files changed, 110 insertions(+) create mode 100644 syft/pkg/cataloger/cpp/parse_conanlock.go create mode 100644 syft/pkg/cataloger/cpp/parse_conanlock_test.go create mode 100644 syft/pkg/cataloger/cpp/test-fixtures/conan.lock diff --git a/syft/pkg/cataloger/cpp/cataloger.go b/syft/pkg/cataloger/cpp/cataloger.go index a8f02877d114..0fb822259b07 100644 --- a/syft/pkg/cataloger/cpp/cataloger.go +++ b/syft/pkg/cataloger/cpp/cataloger.go @@ -8,6 +8,7 @@ import ( func NewConanfileCataloger() *common.GenericCataloger { globParsers := map[string]common.ParserFn{ "**/conanfile.txt": parseConanfile, + "**/conan.lock": parseConanlock, } return common.NewGenericCataloger(nil, globParsers, "conan-cataloger") diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go new file mode 100644 index 000000000000..06045026c7e1 --- /dev/null +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -0,0 +1,52 @@ +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 + +// 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 graphLock struct { + GraphLock struct { + Nodes map[string]struct { + Ref string + } + } `json:"graph_lock"` + } + if err := json.NewDecoder(reader).Decode(&graphLock); err != nil { + return nil, nil, err + } else { + for _, node := range graphLock.GraphLock.Nodes { + if len(node.Ref) > 0 { + // ref: pkga/0.1@user/testing + splits := strings.Split(strings.Split(node.Ref, "@")[0], "/") + if len(splits) < 2 { + continue + } + pkgName, pkgVersion := splits[0], splits[1] + pkgs = append(pkgs, &pkg.Package{ + Name: pkgName, + Version: pkgVersion, + Language: pkg.CPP, + Type: pkg.ConanPkg, + MetadataType: pkg.ConanaMetadataType, + Metadata: pkg.ConanMetadata{ + Name: pkgName, + Version: pkgVersion, + }, + }) + } + } + return pkgs, nil, nil + } +} diff --git a/syft/pkg/cataloger/cpp/parse_conanlock_test.go b/syft/pkg/cataloger/cpp/parse_conanlock_test.go new file mode 100644 index 000000000000..e341d244a76a --- /dev/null +++ b/syft/pkg/cataloger/cpp/parse_conanlock_test.go @@ -0,0 +1,42 @@ +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.ConanaMetadataType, + Metadata: pkg.ConanMetadata{ + Name: "zlib", + Version: "1.2.12", + }, + }, + } + + 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) + } +} diff --git a/syft/pkg/cataloger/cpp/test-fixtures/conan.lock b/syft/pkg/cataloger/cpp/test-fixtures/conan.lock new file mode 100644 index 000000000000..2d3117a96db5 --- /dev/null +++ b/syft/pkg/cataloger/cpp/test-fixtures/conan.lock @@ -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" +} \ No newline at end of file From 96aac3a5804440cd7b70da671e662c741a217c8d Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 13:08:37 -0400 Subject: [PATCH 02/12] update function based on linter error Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanlock.go | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index 06045026c7e1..22b38a39c6de 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -25,28 +25,28 @@ func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela } if err := json.NewDecoder(reader).Decode(&graphLock); err != nil { return nil, nil, err - } else { - for _, node := range graphLock.GraphLock.Nodes { - if len(node.Ref) > 0 { - // ref: pkga/0.1@user/testing - splits := strings.Split(strings.Split(node.Ref, "@")[0], "/") - if len(splits) < 2 { - continue - } - pkgName, pkgVersion := splits[0], splits[1] - pkgs = append(pkgs, &pkg.Package{ - Name: pkgName, - Version: pkgVersion, - Language: pkg.CPP, - Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, - Metadata: pkg.ConanMetadata{ - Name: pkgName, - Version: pkgVersion, - }, - }) + } + for _, node := range graphLock.GraphLock.Nodes { + if len(node.Ref) > 0 { + // ref: pkga/0.1@user/testing + splits := strings.Split(strings.Split(node.Ref, "@")[0], "/") + if len(splits) < 2 { + continue } + pkgName, pkgVersion := splits[0], splits[1] + pkgs = append(pkgs, &pkg.Package{ + Name: pkgName, + Version: pkgVersion, + Language: pkg.CPP, + Type: pkg.ConanPkg, + MetadataType: pkg.ConanaMetadataType, + Metadata: pkg.ConanMetadata{ + Name: pkgName, + Version: pkgVersion, + }, + }) } - return pkgs, nil, nil } + + return pkgs, nil, nil } From 5ad3b0e8071ca5cb3bcff5fda39ae0054d7c473e Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 13:17:21 -0400 Subject: [PATCH 03/12] update struct to not be inline based on review Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanlock.go | 20 ++++++++++--------- .../cataloger/cpp/test-fixtures/conan.lock | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index 22b38a39c6de..3691aec99abf 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -13,20 +13,22 @@ import ( // integrity check var _ common.ParserFn = parseConanlock +type conanLock struct { + GraphLock struct { + Nodes map[string]struct { + Ref string + } + } `json:"graph_lock"` +} + // 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 graphLock struct { - GraphLock struct { - Nodes map[string]struct { - Ref string - } - } `json:"graph_lock"` - } - if err := json.NewDecoder(reader).Decode(&graphLock); err != nil { + var cl conanLock + if err := json.NewDecoder(reader).Decode(&cl); err != nil { return nil, nil, err } - for _, node := range graphLock.GraphLock.Nodes { + for _, node := range cl.GraphLock.Nodes { if len(node.Ref) > 0 { // ref: pkga/0.1@user/testing splits := strings.Split(strings.Split(node.Ref, "@")[0], "/") diff --git a/syft/pkg/cataloger/cpp/test-fixtures/conan.lock b/syft/pkg/cataloger/cpp/test-fixtures/conan.lock index 2d3117a96db5..b63008d90bba 100644 --- a/syft/pkg/cataloger/cpp/test-fixtures/conan.lock +++ b/syft/pkg/cataloger/cpp/test-fixtures/conan.lock @@ -12,4 +12,4 @@ }, "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" -} \ No newline at end of file +} From e72dbe3f266aaaac3569b4c200376a998ff404a9 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 13:28:00 -0400 Subject: [PATCH 04/12] update conanLock with explicit json tags Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanlock.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index 3691aec99abf..6f6057e2106c 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -16,9 +16,14 @@ var _ common.ParserFn = parseConanlock type conanLock struct { GraphLock struct { Nodes map[string]struct { - Ref string - } + Ref string `json:"ref"` + Options string `json:"options"` + Path string `json:"path"` + Context string `json:"context"` + } `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. From d44c78ec042917485e07b872a21534f4654c643b Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 13:59:56 -0400 Subject: [PATCH 05/12] enhance Metadata with lockfile information Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanlock.go | 3 +++ syft/pkg/conan_metadata.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index 6f6057e2106c..c3459df5c969 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -50,6 +50,9 @@ func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela Metadata: pkg.ConanMetadata{ Name: pkgName, Version: pkgVersion, + Options: node.Options, + Path: node.Path, + Context: node.Context, }, }) } diff --git a/syft/pkg/conan_metadata.go b/syft/pkg/conan_metadata.go index 9717e8f3d8f6..bf6637eda021 100644 --- a/syft/pkg/conan_metadata.go +++ b/syft/pkg/conan_metadata.go @@ -8,6 +8,9 @@ import ( type ConanMetadata struct { Name string `mapstructure:"name" json:"name"` Version string `mapstructure:"version" json:"version"` + Options string `mapstructure:"options" json:"options"` + Path string `mapstructure:"path" json:"path"` + Context string `mapstructure:"context" json:"context"` } func (m ConanMetadata) PackageURL(_ *linux.Release) string { From 010e58f81c6ce2a8842acbaa402cd9244929596e Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 15:05:00 -0400 Subject: [PATCH 06/12] update ConanMetadata to better represent Ref - add NameAndVersion method to parse ref from ConanMetadata - update parseConanfile to use new NameAndVersion method - update parseConanfile tests to use Ref vs Name/Version - update parseConanlock to use new NameAndVersion method - update packageurl to test new NameAndVersion method - add ConanMetadata test for PURL parsing Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanfile.go | 16 ++++---- .../pkg/cataloger/cpp/parse_conanfile_test.go | 18 +++----- syft/pkg/cataloger/cpp/parse_conanlock.go | 41 +++++++++---------- .../pkg/cataloger/cpp/parse_conanlock_test.go | 6 ++- syft/pkg/conan_metadata.go | 27 ++++++++++-- syft/pkg/conan_metadata_test.go | 27 ++++++++++++ syft/pkg/url_test.go | 3 +- 7 files changed, 89 insertions(+), 49 deletions(-) create mode 100644 syft/pkg/conan_metadata_test.go diff --git a/syft/pkg/cataloger/cpp/parse_conanfile.go b/syft/pkg/cataloger/cpp/parse_conanfile.go index d3a6481bd39f..90e8cc976559 100644 --- a/syft/pkg/cataloger/cpp/parse_conanfile.go +++ b/syft/pkg/cataloger/cpp/parse_conanfile.go @@ -40,21 +40,23 @@ func parseConanfile(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela inRequirements = false } - splits := strings.Split(strings.TrimSpace(line), "/") - if len(splits) < 2 || !inRequirements { + m := pkg.ConanMetadata{ + Ref: strings.Trim(line, "\n"), + } + + pkgName, pkgVersion := m.NameAndVersion() + + if pkgName == "" || pkgVersion == "" || !inRequirements { continue } - pkgName, pkgVersion := splits[0], splits[1] + pkgs = append(pkgs, &pkg.Package{ Name: pkgName, Version: pkgVersion, Language: pkg.CPP, Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, - Metadata: pkg.ConanMetadata{ - Name: pkgName, - Version: pkgVersion, - }, + Metadata: m, }) } } diff --git a/syft/pkg/cataloger/cpp/parse_conanfile_test.go b/syft/pkg/cataloger/cpp/parse_conanfile_test.go index 4500f0bd8dbd..02842784436e 100644 --- a/syft/pkg/cataloger/cpp/parse_conanfile_test.go +++ b/syft/pkg/cataloger/cpp/parse_conanfile_test.go @@ -18,8 +18,7 @@ func TestParseConanfile(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "catch2", - Version: "2.13.8", + Ref: "catch2/2.13.8", }, }, { @@ -29,8 +28,7 @@ func TestParseConanfile(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "docopt.cpp", - Version: "0.6.3", + Ref: "docopt.cpp/0.6.3", }, }, { @@ -40,8 +38,7 @@ func TestParseConanfile(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "fmt", - Version: "8.1.1", + Ref: "fmt/8.1.1", }, }, { @@ -51,8 +48,7 @@ func TestParseConanfile(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "spdlog", - Version: "1.9.2", + Ref: "spdlog/1.9.2", }, }, { @@ -62,8 +58,7 @@ func TestParseConanfile(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "sdl", - Version: "2.0.20", + Ref: "sdl/2.0.20", }, }, { @@ -73,8 +68,7 @@ func TestParseConanfile(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "fltk", - Version: "1.3.8", + Ref: "fltk/1.3.8", }, }, } diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index c3459df5c969..bde53c4cb7a7 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -3,7 +3,6 @@ package cpp import ( "encoding/json" "io" - "strings" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/pkg" @@ -34,28 +33,26 @@ func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela return nil, nil, err } for _, node := range cl.GraphLock.Nodes { - if len(node.Ref) > 0 { - // ref: pkga/0.1@user/testing - splits := strings.Split(strings.Split(node.Ref, "@")[0], "/") - if len(splits) < 2 { - continue - } - pkgName, pkgVersion := splits[0], splits[1] - pkgs = append(pkgs, &pkg.Package{ - Name: pkgName, - Version: pkgVersion, - Language: pkg.CPP, - Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, - Metadata: pkg.ConanMetadata{ - Name: pkgName, - Version: pkgVersion, - Options: node.Options, - Path: node.Path, - Context: node.Context, - }, - }) + metadata := pkg.ConanMetadata{ + Ref: node.Ref, + Options: 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.ConanaMetadataType, + Metadata: metadata, + }) } return pkgs, nil, nil diff --git a/syft/pkg/cataloger/cpp/parse_conanlock_test.go b/syft/pkg/cataloger/cpp/parse_conanlock_test.go index e341d244a76a..68ccb9b59756 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock_test.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock_test.go @@ -18,8 +18,10 @@ func TestParseConanlock(t *testing.T) { Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, Metadata: pkg.ConanMetadata{ - Name: "zlib", - Version: "1.2.12", + Ref: "zlib/1.2.12", + Options: "fPIC=True\nshared=False", + Path: "all/conanfile.py", + Context: "host", }, }, } diff --git a/syft/pkg/conan_metadata.go b/syft/pkg/conan_metadata.go index bf6637eda021..69edc067e3a1 100644 --- a/syft/pkg/conan_metadata.go +++ b/syft/pkg/conan_metadata.go @@ -1,13 +1,14 @@ package pkg import ( + "strings" + "github.com/anchore/packageurl-go" "github.com/anchore/syft/syft/linux" ) type ConanMetadata struct { - Name string `mapstructure:"name" json:"name"` - Version string `mapstructure:"version" json:"version"` + Ref string `mapstructure:"ref" json:"ref"` Options string `mapstructure:"options" json:"options"` Path string `mapstructure:"path" json:"path"` Context string `mapstructure:"context" json:"context"` @@ -16,12 +17,30 @@ type ConanMetadata struct { func (m ConanMetadata) PackageURL(_ *linux.Release) string { var qualifiers packageurl.Qualifiers + name, version := m.NameAndVersion() + return packageurl.NewPackageURL( packageurl.TypeConan, "", - m.Name, - m.Version, + name, + version, qualifiers, "", ).ToString() } + +// NameAndVersion tries to return the name and version of a cpp package +// given the ref format: pkga/0.1@user/testing +// 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.Split(m.Ref, "@")[0], "/") + if len(splits) < 2 { + return name, version + } + + return splits[0], splits[1] +} diff --git a/syft/pkg/conan_metadata_test.go b/syft/pkg/conan_metadata_test.go new file mode 100644 index 000000000000..9492f0594e57 --- /dev/null +++ b/syft/pkg/conan_metadata_test.go @@ -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: "pkg/1.2.3@user/channel", + }, + want: "pkg:conan/pkg@1.2.3", + }, + } + + 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) + } + }) + } +} diff --git a/syft/pkg/url_test.go b/syft/pkg/url_test.go index 03b689d2d64a..52bc4bdadffb 100644 --- a/syft/pkg/url_test.go +++ b/syft/pkg/url_test.go @@ -241,8 +241,7 @@ func TestPackageURL(t *testing.T) { Language: CPP, MetadataType: ConanaMetadataType, Metadata: ConanMetadata{ - Name: "catch2", - Version: "2.13.8", + Ref: "catch2/2.13.8", }, }, expected: "pkg:conan/catch2@2.13.8", From fea2745dc9648a9af928109503d92bddfd1e1ad1 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 15:12:00 -0400 Subject: [PATCH 07/12] update conanlock to use pkg.ConanMetadata Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanlock.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index bde53c4cb7a7..24205d82df6f 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -14,12 +14,7 @@ var _ common.ParserFn = parseConanlock type conanLock struct { GraphLock struct { - Nodes map[string]struct { - Ref string `json:"ref"` - Options string `json:"options"` - Path string `json:"path"` - Context string `json:"context"` - } `json:"nodes"` + Nodes map[string]pkg.ConanMetadata `json:"nodes"` } `json:"graph_lock"` Version string `json:"version"` ProfileHost string `json:"profile_host"` From d3ed04191b9cf2bfed6a9981fa1883c59b32068c Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 28 Sep 2022 17:18:26 -0400 Subject: [PATCH 08/12] add new ConanLockMetadata - add conan_lock_metadata to use for conan lock Parser - revert changes to conan metadata - update inline struct for conan lock parser to match all fields - update tests to match new parsing of conan lock options Signed-off-by: Christopher Phillips --- syft/pkg/cataloger/cpp/parse_conanlock.go | 37 ++++++++++++++-- .../pkg/cataloger/cpp/parse_conanlock_test.go | 9 ++-- syft/pkg/conan_lock_metadata.go | 43 +++++++++++++++++++ syft/pkg/conan_metadata.go | 10 ++--- syft/pkg/conan_metadata_test.go | 4 +- 5 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 syft/pkg/conan_lock_metadata.go diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index 24205d82df6f..a745d07a30f0 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -3,6 +3,7 @@ package cpp import ( "encoding/json" "io" + "strings" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/pkg" @@ -14,7 +15,20 @@ var _ common.ParserFn = parseConanlock type conanLock struct { GraphLock struct { - Nodes map[string]pkg.ConanMetadata `json:"nodes"` + 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"` + RevisionsEnabled string `json:"revisions_enabled"` + Relaxed string `json:"relaxed"` + Modified string `json:"modified"` + Path string `json:"path"` + } `json:"nodes"` } `json:"graph_lock"` Version string `json:"version"` ProfileHost string `json:"profile_host"` @@ -28,9 +42,9 @@ func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela return nil, nil, err } for _, node := range cl.GraphLock.Nodes { - metadata := pkg.ConanMetadata{ + metadata := pkg.ConanLockMetadata{ Ref: node.Ref, - Options: node.Options, + Options: parseOptions(node.Options), Path: node.Path, Context: node.Context, } @@ -52,3 +66,20 @@ func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela 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 +} diff --git a/syft/pkg/cataloger/cpp/parse_conanlock_test.go b/syft/pkg/cataloger/cpp/parse_conanlock_test.go index 68ccb9b59756..13367563c64d 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock_test.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock_test.go @@ -17,9 +17,12 @@ func TestParseConanlock(t *testing.T) { Language: pkg.CPP, Type: pkg.ConanPkg, MetadataType: pkg.ConanaMetadataType, - Metadata: pkg.ConanMetadata{ - Ref: "zlib/1.2.12", - Options: "fPIC=True\nshared=False", + Metadata: pkg.ConanLockMetadata{ + Ref: "zlib/1.2.12", + Options: map[string]string{ + "fPIC": "True", + "shared": "False", + }, Path: "all/conanfile.py", Context: "host", }, diff --git a/syft/pkg/conan_lock_metadata.go b/syft/pkg/conan_lock_metadata.go new file mode 100644 index 000000000000..2a7bab60c433 --- /dev/null +++ b/syft/pkg/conan_lock_metadata.go @@ -0,0 +1,43 @@ +package pkg + +import ( + "strings" + + "github.com/anchore/packageurl-go" + "github.com/anchore/syft/syft/linux" +) + +type ConanLockMetadata struct { + Ref string `json:"ref"` + Options map[string]string `json:"options"` + Path string `json:"path"` + Context string `json:"context"` +} + +func (m ConanLockMetadata) PackageURL(_ *linux.Release) string { + var qualifiers packageurl.Qualifiers + + name, version := m.NameAndVersion() + + return packageurl.NewPackageURL( + packageurl.TypeConan, + "", + name, + version, + qualifiers, + "", + ).ToString() +} + +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] +} diff --git a/syft/pkg/conan_metadata.go b/syft/pkg/conan_metadata.go index 69edc067e3a1..1e287ba735b4 100644 --- a/syft/pkg/conan_metadata.go +++ b/syft/pkg/conan_metadata.go @@ -8,10 +8,7 @@ import ( ) type ConanMetadata struct { - Ref string `mapstructure:"ref" json:"ref"` - Options string `mapstructure:"options" json:"options"` - Path string `mapstructure:"path" json:"path"` - Context string `mapstructure:"context" json:"context"` + Ref string `mapstructure:"ref" json:"ref"` } func (m ConanMetadata) PackageURL(_ *linux.Release) string { @@ -30,14 +27,15 @@ func (m ConanMetadata) PackageURL(_ *linux.Release) string { } // NameAndVersion tries to return the name and version of a cpp package -// given the ref format: pkga/0.1@user/testing +// 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.Split(m.Ref, "@")[0], "/") + splits := strings.Split(strings.TrimSpace(m.Ref), "/") + if len(splits) < 2 { return name, version } diff --git a/syft/pkg/conan_metadata_test.go b/syft/pkg/conan_metadata_test.go index 9492f0594e57..7bf13cf41017 100644 --- a/syft/pkg/conan_metadata_test.go +++ b/syft/pkg/conan_metadata_test.go @@ -11,9 +11,9 @@ func TestConanMetadata_PackageURL(t *testing.T) { { name: "happy path", m: ConanMetadata{ - Ref: "pkg/1.2.3@user/channel", + Ref: "catch2/2.13.8", }, - want: "pkg:conan/pkg@1.2.3", + want: "pkg:conan/catch2@2.13.8", }, } From c25aa3844fedfe49534a640ac2307a74bec9682d Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Thu, 29 Sep 2022 11:34:36 -0400 Subject: [PATCH 09/12] generate new schema - BREAKING: change ConanMetadata to use ref - ADDITION: add ConanaLockMetadata type Signed-off-by: Christopher Phillips --- internal/constants.go | 2 +- schema/json/schema-4.0.0.json | 1471 +++++++++++++++++ syft/formats/syftjson/model/package.go | 8 +- .../snapshot/TestDirectoryEncoder.golden | 4 +- .../TestEncodeFullJSONDocument.golden | 4 +- .../snapshot/TestImageEncoder.golden | 4 +- syft/pkg/cataloger/cpp/parse_conanfile.go | 2 +- .../pkg/cataloger/cpp/parse_conanfile_test.go | 12 +- syft/pkg/cataloger/cpp/parse_conanlock.go | 23 +- .../pkg/cataloger/cpp/parse_conanlock_test.go | 2 +- syft/pkg/conan_lock_metadata.go | 15 +- syft/pkg/conan_lock_metadata_test.go | 1 + syft/pkg/metadata.go | 9 +- syft/pkg/url_test.go | 18 +- 14 files changed, 1538 insertions(+), 37 deletions(-) create mode 100644 schema/json/schema-4.0.0.json create mode 100644 syft/pkg/conan_lock_metadata_test.go diff --git a/internal/constants.go b/internal/constants.go index 6fcf68a47938..71a134a72a92 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -6,5 +6,5 @@ const ( // 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. - JSONSchemaVersion = "3.3.2" + JSONSchemaVersion = "4.0.0" ) diff --git a/schema/json/schema-4.0.0.json b/schema/json/schema-4.0.0.json new file mode 100644 index 000000000000..bb963c26f7e9 --- /dev/null +++ b/schema/json/schema-4.0.0.json @@ -0,0 +1,1471 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Document", + "definitions": { + "AlpmFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "type": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "size": { + "type": "string" + }, + "link": { + "type": "string" + }, + "digest": { + "items": { + "$ref": "#/definitions/Digest" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "AlpmMetadata": { + "required": [ + "basepackage", + "package", + "version", + "description", + "architecture", + "size", + "packager", + "license", + "url", + "validation", + "reason", + "files", + "backup" + ], + "properties": { + "basepackage": { + "type": "string" + }, + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "packager": { + "type": "string" + }, + "license": { + "type": "string" + }, + "url": { + "type": "string" + }, + "validation": { + "type": "string" + }, + "reason": { + "type": "integer" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/AlpmFileRecord" + }, + "type": "array" + }, + "backup": { + "items": { + "$ref": "#/definitions/AlpmFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "ApkFileRecord": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "ownerUid": { + "type": "string" + }, + "ownerGid": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "digest": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Digest" + } + }, + "additionalProperties": true, + "type": "object" + }, + "ApkMetadata": { + "required": [ + "package", + "originPackage", + "maintainer", + "version", + "license", + "architecture", + "url", + "description", + "size", + "installedSize", + "pullDependencies", + "pullChecksum", + "gitCommitOfApkPort", + "files" + ], + "properties": { + "package": { + "type": "string" + }, + "originPackage": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "installedSize": { + "type": "integer" + }, + "pullDependencies": { + "type": "string" + }, + "pullChecksum": { + "type": "string" + }, + "gitCommitOfApkPort": { + "type": "string" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/ApkFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "CargoPackageMetadata": { + "required": [ + "name", + "version", + "source", + "checksum", + "dependencies" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "type": "string" + }, + "checksum": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Classification": { + "required": [ + "class", + "metadata" + ], + "properties": { + "class": { + "type": "string" + }, + "metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Coordinates": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DartPubMetadata": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "hosted_url": { + "type": "string" + }, + "vcs_url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Descriptor": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "configuration": { + "additionalProperties": true + } + }, + "additionalProperties": true, + "type": "object" + }, + "Digest": { + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Document": { + "required": [ + "artifacts", + "artifactRelationships", + "source", + "distro", + "descriptor", + "schema" + ], + "properties": { + "artifacts": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Package" + }, + "type": "array" + }, + "artifactRelationships": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Relationship" + }, + "type": "array" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/File" + }, + "type": "array" + }, + "secrets": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Secrets" + }, + "type": "array" + }, + "source": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Source" + }, + "distro": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/LinuxRelease" + }, + "descriptor": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Descriptor" + }, + "schema": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Schema" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DotnetDepsMetadata": { + "required": [ + "name", + "version", + "path", + "sha512", + "hashPath" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "path": { + "type": "string" + }, + "sha512": { + "type": "string" + }, + "hashPath": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DpkgFileRecord": { + "required": [ + "path", + "isConfigFile" + ], + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/definitions/Digest" + }, + "isConfigFile": { + "type": "boolean" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DpkgMetadata": { + "required": [ + "package", + "source", + "version", + "sourceVersion", + "architecture", + "maintainer", + "installedSize", + "files" + ], + "properties": { + "package": { + "type": "string" + }, + "source": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/DpkgFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "File": { + "required": [ + "id", + "location" + ], + "properties": { + "id": { + "type": "string" + }, + "location": { + "$ref": "#/definitions/Coordinates" + }, + "metadata": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/FileMetadataEntry" + }, + "contents": { + "type": "string" + }, + "digests": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Digest" + }, + "type": "array" + }, + "classifications": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Classification" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "FileMetadataEntry": { + "required": [ + "mode", + "type", + "userID", + "groupID", + "mimeType" + ], + "properties": { + "mode": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "linkDestination": { + "type": "string" + }, + "userID": { + "type": "integer" + }, + "groupID": { + "type": "integer" + }, + "mimeType": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "GemMetadata": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "type": "string" + }, + "type": "array" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "GolangBinMetadata": { + "required": [ + "goCompiledVersion", + "architecture" + ], + "properties": { + "goBuildSettings": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "goCompiledVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "h1Digest": { + "type": "string" + }, + "mainModule": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "JavaManifest": { + "properties": { + "main": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "namedSections": { + "patternProperties": { + ".*": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "additionalProperties": true, + "type": "object" + }, + "JavaMetadata": { + "required": [ + "virtualPath" + ], + "properties": { + "virtualPath": { + "type": "string" + }, + "manifest": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/JavaManifest" + }, + "pomProperties": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PomProperties" + }, + "pomProject": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PomProject" + }, + "digest": { + "items": { + "$ref": "#/definitions/Digest" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "LinuxRelease": { + "properties": { + "prettyName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "idLike": { + "items": { + "type": "string" + }, + "type": "array" + }, + "version": { + "type": "string" + }, + "versionID": { + "type": "string" + }, + "versionCodename": { + "type": "string" + }, + "buildID": { + "type": "string" + }, + "imageID": { + "type": "string" + }, + "imageVersion": { + "type": "string" + }, + "variant": { + "type": "string" + }, + "variantID": { + "type": "string" + }, + "homeURL": { + "type": "string" + }, + "supportURL": { + "type": "string" + }, + "bugReportURL": { + "type": "string" + }, + "privacyPolicyURL": { + "type": "string" + }, + "cpeName": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "NpmPackageJSONMetadata": { + "required": [ + "name", + "version", + "author", + "licenses", + "homepage", + "description", + "url", + "private" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "type": "string" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "private": { + "type": "boolean" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Package": { + "required": [ + "id", + "name", + "version", + "type", + "foundBy", + "locations", + "licenses", + "language", + "cpes", + "purl" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "foundBy": { + "type": "string" + }, + "locations": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Coordinates" + }, + "type": "array" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "language": { + "type": "string" + }, + "cpes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "purl": { + "type": "string" + }, + "metadataType": { + "type": "string" + }, + "metadata": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/definitions/AlpmMetadata" + }, + { + "$ref": "#/definitions/ApkMetadata" + }, + { + "$ref": "#/definitions/CargoPackageMetadata" + }, + { + "$ref": "#/definitions/DartPubMetadata" + }, + { + "$ref": "#/definitions/DotnetDepsMetadata" + }, + { + "$ref": "#/definitions/DpkgMetadata" + }, + { + "$ref": "#/definitions/GemMetadata" + }, + { + "$ref": "#/definitions/GolangBinMetadata" + }, + { + "$ref": "#/definitions/JavaMetadata" + }, + { + "$ref": "#/definitions/NpmPackageJSONMetadata" + }, + { + "$ref": "#/definitions/PhpComposerJSONMetadata" + }, + { + "$ref": "#/definitions/PortageMetadata" + }, + { + "$ref": "#/definitions/PythonPackageMetadata" + }, + { + "$ref": "#/definitions/RpmMetadata" + } + ] + } + }, + "additionalProperties": true, + "type": "object" + }, + "PhpComposerAuthors": { + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "homepage": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PhpComposerExternalReference": { + "required": [ + "type", + "url", + "reference" + ], + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "shasum": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PhpComposerJSONMetadata": { + "required": [ + "name", + "version", + "source", + "dist" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PhpComposerExternalReference" + }, + "dist": { + "$ref": "#/definitions/PhpComposerExternalReference" + }, + "require": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "provide": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "require-dev": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "suggest": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "notification-url": { + "type": "string" + }, + "bin": { + "items": { + "type": "string" + }, + "type": "array" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PhpComposerAuthors" + }, + "type": "array" + }, + "description": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "keywords": { + "items": { + "type": "string" + }, + "type": "array" + }, + "time": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PomParent": { + "required": [ + "groupId", + "artifactId", + "version" + ], + "properties": { + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PomProject": { + "required": [ + "path", + "groupId", + "artifactId", + "version", + "name" + ], + "properties": { + "path": { + "type": "string" + }, + "parent": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PomParent" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PomProperties": { + "required": [ + "path", + "name", + "groupId", + "artifactId", + "version", + "extraFields" + ], + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "extraFields": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PortageFileRecord": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/definitions/Digest" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PortageMetadata": { + "required": [ + "package", + "version", + "installedSize", + "files" + ], + "properties": { + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PortageFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonDirectURLOriginInfo": { + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string" + }, + "commitId": { + "type": "string" + }, + "vcs": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonFileDigest": { + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonFileRecord": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PythonFileDigest" + }, + "size": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonPackageMetadata": { + "required": [ + "name", + "version", + "license", + "author", + "authorEmail", + "platform", + "sitePackagesRootPath" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorEmail": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PythonFileRecord" + }, + "type": "array" + }, + "sitePackagesRootPath": { + "type": "string" + }, + "topLevelPackages": { + "items": { + "type": "string" + }, + "type": "array" + }, + "directUrlOrigin": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PythonDirectURLOriginInfo" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Relationship": { + "required": [ + "parent", + "child", + "type" + ], + "properties": { + "parent": { + "type": "string" + }, + "child": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": { + "additionalProperties": true + } + }, + "additionalProperties": true, + "type": "object" + }, + "RpmMetadata": { + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "license", + "vendor", + "modularityLabel", + "files" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "epoch": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "architecture": { + "type": "string" + }, + "release": { + "type": "string" + }, + "sourceRpm": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "license": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "modularityLabel": { + "type": "string" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/RpmdbFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "RpmdbFileRecord": { + "required": [ + "path", + "mode", + "size", + "digest", + "userName", + "groupName", + "flags" + ], + "properties": { + "path": { + "type": "string" + }, + "mode": { + "type": "integer" + }, + "size": { + "type": "integer" + }, + "digest": { + "$ref": "#/definitions/Digest" + }, + "userName": { + "type": "string" + }, + "groupName": { + "type": "string" + }, + "flags": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Schema": { + "required": [ + "version", + "url" + ], + "properties": { + "version": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "SearchResult": { + "required": [ + "classification", + "lineNumber", + "lineOffset", + "seekPosition", + "length" + ], + "properties": { + "classification": { + "type": "string" + }, + "lineNumber": { + "type": "integer" + }, + "lineOffset": { + "type": "integer" + }, + "seekPosition": { + "type": "integer" + }, + "length": { + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Secrets": { + "required": [ + "location", + "secrets" + ], + "properties": { + "location": { + "$ref": "#/definitions/Coordinates" + }, + "secrets": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/SearchResult" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Source": { + "required": [ + "type", + "target" + ], + "properties": { + "type": { + "type": "string" + }, + "target": { + "additionalProperties": true + } + }, + "additionalProperties": true, + "type": "object" + } + } +} diff --git a/syft/formats/syftjson/model/package.go b/syft/formats/syftjson/model/package.go index 7249af296e01..b2fd9190322e 100644 --- a/syft/formats/syftjson/model/package.go +++ b/syft/formats/syftjson/model/package.go @@ -163,12 +163,18 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error { return err } p.Metadata = payload - case pkg.ConanaMetadataType: + case pkg.ConanMetadataType: var payload pkg.ConanMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } 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: var payload pkg.DotnetDepsMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { diff --git a/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden b/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden index 19a8f5044f14..f7118ea6d234 100644 --- a/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden +++ b/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden @@ -88,7 +88,7 @@ } }, "schema": { - "version": "3.3.2", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json" + "version": "4.0.0", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-4.0.0.json" } } diff --git a/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden b/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden index 2b474a2810db..664b82f9cb5e 100644 --- a/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden +++ b/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden @@ -184,7 +184,7 @@ } }, "schema": { - "version": "3.3.2", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json" + "version": "4.0.0", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-4.0.0.json" } } diff --git a/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden b/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden index ae948591c5ff..a7dda4af6cb0 100644 --- a/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden +++ b/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden @@ -111,7 +111,7 @@ } }, "schema": { - "version": "3.3.2", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json" + "version": "4.0.0", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-4.0.0.json" } } diff --git a/syft/pkg/cataloger/cpp/parse_conanfile.go b/syft/pkg/cataloger/cpp/parse_conanfile.go index 90e8cc976559..e3c70a90d40f 100644 --- a/syft/pkg/cataloger/cpp/parse_conanfile.go +++ b/syft/pkg/cataloger/cpp/parse_conanfile.go @@ -55,7 +55,7 @@ func parseConanfile(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela Version: pkgVersion, Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: m, }) } diff --git a/syft/pkg/cataloger/cpp/parse_conanfile_test.go b/syft/pkg/cataloger/cpp/parse_conanfile_test.go index 02842784436e..253fc6b0a939 100644 --- a/syft/pkg/cataloger/cpp/parse_conanfile_test.go +++ b/syft/pkg/cataloger/cpp/parse_conanfile_test.go @@ -16,7 +16,7 @@ func TestParseConanfile(t *testing.T) { Version: "2.13.8", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: pkg.ConanMetadata{ Ref: "catch2/2.13.8", }, @@ -26,7 +26,7 @@ func TestParseConanfile(t *testing.T) { Version: "0.6.3", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: pkg.ConanMetadata{ Ref: "docopt.cpp/0.6.3", }, @@ -36,7 +36,7 @@ func TestParseConanfile(t *testing.T) { Version: "8.1.1", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: pkg.ConanMetadata{ Ref: "fmt/8.1.1", }, @@ -46,7 +46,7 @@ func TestParseConanfile(t *testing.T) { Version: "1.9.2", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: pkg.ConanMetadata{ Ref: "spdlog/1.9.2", }, @@ -56,7 +56,7 @@ func TestParseConanfile(t *testing.T) { Version: "2.0.20", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: pkg.ConanMetadata{ Ref: "sdl/2.0.20", }, @@ -66,7 +66,7 @@ func TestParseConanfile(t *testing.T) { Version: "1.3.8", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanMetadataType, Metadata: pkg.ConanMetadata{ Ref: "fltk/1.3.8", }, diff --git a/syft/pkg/cataloger/cpp/parse_conanlock.go b/syft/pkg/cataloger/cpp/parse_conanlock.go index a745d07a30f0..85fcf1c035fe 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock.go @@ -16,18 +16,15 @@ 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"` - RevisionsEnabled string `json:"revisions_enabled"` - Relaxed string `json:"relaxed"` - Modified string `json:"modified"` - Path string `json:"path"` + 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"` @@ -59,7 +56,7 @@ func parseConanlock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Rela Version: pkgVersion, Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanLockMetadataType, Metadata: metadata, }) } diff --git a/syft/pkg/cataloger/cpp/parse_conanlock_test.go b/syft/pkg/cataloger/cpp/parse_conanlock_test.go index 13367563c64d..ffb2b7c84b61 100644 --- a/syft/pkg/cataloger/cpp/parse_conanlock_test.go +++ b/syft/pkg/cataloger/cpp/parse_conanlock_test.go @@ -16,7 +16,7 @@ func TestParseConanlock(t *testing.T) { Version: "1.2.12", Language: pkg.CPP, Type: pkg.ConanPkg, - MetadataType: pkg.ConanaMetadataType, + MetadataType: pkg.ConanLockMetadataType, Metadata: pkg.ConanLockMetadata{ Ref: "zlib/1.2.12", Options: map[string]string{ diff --git a/syft/pkg/conan_lock_metadata.go b/syft/pkg/conan_lock_metadata.go index 2a7bab60c433..401c6748131b 100644 --- a/syft/pkg/conan_lock_metadata.go +++ b/syft/pkg/conan_lock_metadata.go @@ -8,10 +8,15 @@ import ( ) type ConanLockMetadata struct { - Ref string `json:"ref"` - Options map[string]string `json:"options"` - Path string `json:"path"` - Context string `json:"context"` + 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 { @@ -29,6 +34,8 @@ func (m ConanLockMetadata) PackageURL(_ *linux.Release) string { ).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 diff --git a/syft/pkg/conan_lock_metadata_test.go b/syft/pkg/conan_lock_metadata_test.go new file mode 100644 index 000000000000..c1caffeb1fbe --- /dev/null +++ b/syft/pkg/conan_lock_metadata_test.go @@ -0,0 +1 @@ +package pkg diff --git a/syft/pkg/metadata.go b/syft/pkg/metadata.go index 99e8d0839fa2..6a93f78723f8 100644 --- a/syft/pkg/metadata.go +++ b/syft/pkg/metadata.go @@ -26,7 +26,8 @@ const ( GolangBinMetadataType MetadataType = "GolangBinMetadata" PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata" CocoapodsMetadataType MetadataType = "CocoapodsMetadataType" - ConanaMetadataType MetadataType = "ConanaMetadataType" + ConanMetadataType MetadataType = "ConanMetadataType" + ConanLockMetadataType MetadataType = "ConanLockMetadataType" PortageMetadataType MetadataType = "PortageMetadata" HackageMetadataType MetadataType = "HackageMetadataType" ) @@ -47,7 +48,8 @@ var AllMetadataTypes = []MetadataType{ GolangBinMetadataType, PhpComposerJSONMetadataType, CocoapodsMetadataType, - ConanaMetadataType, + ConanMetadataType, + ConanLockMetadataType, PortageMetadataType, HackageMetadataType, } @@ -68,7 +70,8 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{ GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}), PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}), CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}), - ConanaMetadataType: reflect.TypeOf(ConanMetadata{}), + ConanMetadataType: reflect.TypeOf(ConanMetadata{}), + ConanLockMetadataType: reflect.TypeOf(ConanLockMetadata{}), PortageMetadataType: reflect.TypeOf(PortageMetadata{}), HackageMetadataType: reflect.TypeOf(HackageMetadata{}), } diff --git a/syft/pkg/url_test.go b/syft/pkg/url_test.go index 52bc4bdadffb..e2a01af91a4e 100644 --- a/syft/pkg/url_test.go +++ b/syft/pkg/url_test.go @@ -239,13 +239,29 @@ func TestPackageURL(t *testing.T) { Version: "2.13.8", Type: ConanPkg, Language: CPP, - MetadataType: ConanaMetadataType, + MetadataType: ConanMetadataType, Metadata: ConanMetadata{ Ref: "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", pkg: Package{ From 6401db39d11a304f683a71db7ecf18e9d256b2af Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Thu, 29 Sep 2022 13:56:06 -0400 Subject: [PATCH 10/12] update with correct metadata inclusion Signed-off-by: Christopher Phillips --- schema/json/generate.go | 33 ++++++----- schema/json/schema-4.0.0.json | 103 ++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 14 deletions(-) diff --git a/schema/json/generate.go b/schema/json/generate.go index e5833e5ffd6b..31b307a9d8b0 100644 --- a/schema/json/generate.go +++ b/schema/json/generate.go @@ -28,20 +28,25 @@ 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 // not matter as long as it is exported. type artifactMetadataContainer struct { - Apk pkg.ApkMetadata - Alpm pkg.AlpmMetadata - Dpkg pkg.DpkgMetadata - Gem pkg.GemMetadata - Java pkg.JavaMetadata - Npm pkg.NpmPackageJSONMetadata - Python pkg.PythonPackageMetadata - Rpm pkg.RpmMetadata - Cargo pkg.CargoPackageMetadata - Go pkg.GolangBinMetadata - Php pkg.PhpComposerJSONMetadata - Dart pkg.DartPubMetadata - Dotnet pkg.DotnetDepsMetadata - Portage pkg.PortageMetadata + Apk pkg.ApkMetadata + Alpm pkg.AlpmMetadata + Dpkg pkg.DpkgMetadata + Gem pkg.GemMetadata + Java pkg.JavaMetadata + Npm pkg.NpmPackageJSONMetadata + Python pkg.PythonPackageMetadata + Rpm pkg.RpmMetadata + Cargo pkg.CargoPackageMetadata + Go pkg.GolangBinMetadata + Php pkg.PhpComposerJSONMetadata + Dart pkg.DartPubMetadata + Dotnet pkg.DotnetDepsMetadata + Portage pkg.PortageMetadata + Conan pkg.ConanMetadata + ConanLock pkg.ConanLockMetadata + RustCargo pkg.CargoPackageMetadata + KbPackage pkg.KbPackageMetadata + Hackage pkg.HackageMetadata } func main() { diff --git a/schema/json/schema-4.0.0.json b/schema/json/schema-4.0.0.json index bb963c26f7e9..c12add6ba1c0 100644 --- a/schema/json/schema-4.0.0.json +++ b/schema/json/schema-4.0.0.json @@ -248,6 +248,59 @@ "additionalProperties": true, "type": "object" }, + "ConanLockMetadata": { + "required": [ + "ref" + ], + "properties": { + "ref": { + "type": "string" + }, + "package_id": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "requires": { + "type": "string" + }, + "build_requires": { + "type": "string" + }, + "py_requires": { + "type": "string" + }, + "options": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "path": { + "type": "string" + }, + "context": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "ConanMetadata": { + "required": [ + "ref" + ], + "properties": { + "ref": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, "Coordinates": { "required": [ "path" @@ -604,6 +657,28 @@ "additionalProperties": true, "type": "object" }, + "HackageMetadata": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "snapshotURL": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, "JavaManifest": { "properties": { "main": { @@ -661,6 +736,22 @@ "additionalProperties": true, "type": "object" }, + "KbPackageMetadata": { + "required": [ + "product_id", + "kb" + ], + "properties": { + "product_id": { + "type": "string" + }, + "kb": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, "LinuxRelease": { "properties": { "prettyName": { @@ -841,6 +932,12 @@ { "$ref": "#/definitions/CargoPackageMetadata" }, + { + "$ref": "#/definitions/ConanLockMetadata" + }, + { + "$ref": "#/definitions/ConanMetadata" + }, { "$ref": "#/definitions/DartPubMetadata" }, @@ -856,9 +953,15 @@ { "$ref": "#/definitions/GolangBinMetadata" }, + { + "$ref": "#/definitions/HackageMetadata" + }, { "$ref": "#/definitions/JavaMetadata" }, + { + "$ref": "#/definitions/KbPackageMetadata" + }, { "$ref": "#/definitions/NpmPackageJSONMetadata" }, From be74c52d6daf98b1ad6053e5994735503631ac9c Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Thu, 29 Sep 2022 13:59:33 -0400 Subject: [PATCH 11/12] remove duplicate type Signed-off-by: Christopher Phillips --- schema/json/generate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/schema/json/generate.go b/schema/json/generate.go index 31b307a9d8b0..4175ca29b36e 100644 --- a/schema/json/generate.go +++ b/schema/json/generate.go @@ -44,7 +44,6 @@ type artifactMetadataContainer struct { Portage pkg.PortageMetadata Conan pkg.ConanMetadata ConanLock pkg.ConanLockMetadata - RustCargo pkg.CargoPackageMetadata KbPackage pkg.KbPackageMetadata Hackage pkg.HackageMetadata } From 20560be9b37b813367a39537b1dd988df5dc259c Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Thu, 29 Sep 2022 14:22:09 -0400 Subject: [PATCH 12/12] add PURL test back for ConanLockMetadata Signed-off-by: Christopher Phillips --- syft/pkg/conan_lock_metadata_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/syft/pkg/conan_lock_metadata_test.go b/syft/pkg/conan_lock_metadata_test.go index c1caffeb1fbe..9c215d6ac3ba 100644 --- a/syft/pkg/conan_lock_metadata_test.go +++ b/syft/pkg/conan_lock_metadata_test.go @@ -1 +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) + } + }) + } +}