From 67d8f250bd1da30455b522599780ff2f38d8e947 Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Wed, 28 Sep 2022 11:00:51 +0900 Subject: [PATCH] [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 a8f02877d11..0fb822259b0 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 00000000000..06045026c7e --- /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 00000000000..e341d244a76 --- /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 00000000000..2d3117a96db --- /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