Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: properly parse conan ref and include user and channel #2034

Merged
merged 2 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 70 additions & 25 deletions syft/pkg/cataloger/cpp/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,67 @@ import (
"github.com/anchore/syft/syft/pkg"
)

func newConanfilePackage(m pkg.ConanMetadata, locations ...file.Location) *pkg.Package {
fields := strings.Split(strings.TrimSpace(m.Ref), "/")
if len(fields) < 2 {
return nil
type conanRef struct {
Name string
Version string
User string
Channel string
Revision string
Timestamp string
}

func splitConanRef(ref string) *conanRef {
// Conan ref format is:
// pkg/0.1@user/channel#rrev%timestamp
// This method is based on conan's ref.loads method:
// https://github.com/conan-io/conan/blob/release/2.0/conans/model/recipe_ref.py#L93C21-L93C21

var cref conanRef

// timestamp
tokens := strings.Split(ref, "%")
text := tokens[0]
if len(tokens) == 2 {
cref.Timestamp = tokens[1]
}

pkgName, pkgVersion := fields[0], fields[1]
// revision
tokens = strings.Split(text, "#")
ref = tokens[0]
if len(tokens) == 2 {
cref.Revision = tokens[1]
}

if pkgName == "" || pkgVersion == "" {
// name and version are always given
tokens = strings.Split(ref, "@")
nameAndVersion := strings.Split(tokens[0], "/")
if len(nameAndVersion) < 2 || nameAndVersion[0] == "" || nameAndVersion[1] == "" {
return nil
}
cref.Name = nameAndVersion[0]
cref.Version = nameAndVersion[1]
// user and channel
if len(tokens) == 2 && tokens[1] != "" {
tokens = strings.Split(tokens[1], "/")
if len(tokens) == 2 {
cref.User = tokens[0]
cref.Channel = tokens[1]
}
}
return &cref
}

func newConanfilePackage(m pkg.ConanMetadata, locations ...file.Location) *pkg.Package {
ref := splitConanRef(m.Ref)
if ref == nil {
return nil
}

p := pkg.Package{
Name: pkgName,
Version: pkgVersion,
Name: ref.Name,
Version: ref.Version,
Locations: file.NewLocationSet(locations...),
PURL: packageURL(pkgName, pkgVersion),
PURL: packageURL(ref),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Expand All @@ -37,22 +81,16 @@ func newConanfilePackage(m pkg.ConanMetadata, locations ...file.Location) *pkg.P
}

func newConanlockPackage(m pkg.ConanLockMetadata, locations ...file.Location) *pkg.Package {
fields := strings.Split(strings.Split(m.Ref, "@")[0], "/")
if len(fields) < 2 {
return nil
}

pkgName, pkgVersion := fields[0], fields[1]

if pkgName == "" || pkgVersion == "" {
ref := splitConanRef(m.Ref)
if ref == nil {
return nil
}

p := pkg.Package{
Name: pkgName,
Version: pkgVersion,
Name: ref.Name,
Version: ref.Version,
Locations: file.NewLocationSet(locations...),
PURL: packageURL(pkgName, pkgVersion),
PURL: packageURL(ref),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanLockMetadataType,
Expand All @@ -64,13 +102,20 @@ func newConanlockPackage(m pkg.ConanLockMetadata, locations ...file.Location) *p
return &p
}

func packageURL(name, version string) string {
func packageURL(ref *conanRef) string {
qualifiers := packageurl.Qualifiers{}
if ref.Channel != "" {
qualifiers = append(qualifiers, packageurl.Qualifier{
Key: "channel",
Value: ref.Channel,
})
}
return packageurl.NewPackageURL(
packageurl.TypeConan,
"",
name,
version,
nil, // TODO: no qualifiers (...yet)
ref.User,
ref.Name,
ref.Version,
qualifiers,
"",
).ToString()
}
2 changes: 1 addition & 1 deletion syft/pkg/cataloger/cpp/parse_conanfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func parseConanfile(_ file.Resolver, _ *generic.Environment, reader file.Locatio
switch {
case strings.Contains(line, "[requires]"):
inRequirements = true
case strings.ContainsAny(line, "[]#"):
case strings.ContainsAny(line, "[]") || strings.HasPrefix(strings.TrimSpace(line), "#"):
inRequirements = false
}

Expand Down
10 changes: 5 additions & 5 deletions syft/pkg/cataloger/cpp/parse_conanfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ func TestParseConanfile(t *testing.T) {
{
Name: "spdlog",
Version: "1.9.2",
PURL: "pkg:conan/spdlog@1.9.2",
PURL: "pkg:conan/my_user/spdlog@1.9.2?channel=my_channel",
Locations: fixtureLocationSet,
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Metadata: pkg.ConanMetadata{
Ref: "spdlog/1.9.2",
Ref: "spdlog/1.9.2@my_user/my_channel#1234567%%987654",
},
},
{
Expand All @@ -70,19 +70,19 @@ func TestParseConanfile(t *testing.T) {
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Metadata: pkg.ConanMetadata{
Ref: "sdl/2.0.20",
Ref: "sdl/2.0.20#1234567%%987654",
},
},
{
Name: "fltk",
Version: "1.3.8",
PURL: "pkg:conan/fltk@1.3.8",
PURL: "pkg:conan/my_user/fltk@1.3.8?channel=my_channel",
Locations: fixtureLocationSet,
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Metadata: pkg.ConanMetadata{
Ref: "fltk/1.3.8",
Ref: "fltk/1.3.8@my_user/my_channel",
},
},
}
Expand Down
43 changes: 36 additions & 7 deletions syft/pkg/cataloger/cpp/parse_conanlock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,49 @@ func TestParseConanlock(t *testing.T) {
fixture := "test-fixtures/conan.lock"
expected := []pkg.Package{
{
Name: "zlib",
Version: "1.2.12",
PURL: "pkg:conan/zlib@1.2.12",
Name: "spdlog",
Version: "1.11.0",
PURL: "pkg:conan/spdlog@1.11.0",
Locations: file.NewLocationSet(file.NewLocation(fixture)),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanLockMetadataType,
Metadata: pkg.ConanLockMetadata{
Ref: "zlib/1.2.12",
Ref: "spdlog/1.11.0",
Options: map[string]string{
"fPIC": "True",
"shared": "False",
"fPIC": "True",
"header_only": "False",
"no_exceptions": "False",
"shared": "False",
"wchar_filenames": "False",
"wchar_support": "False",
"fmt:fPIC": "True",
"fmt:header_only": "False",
"fmt:shared": "False",
"fmt:with_fmt_alias": "False",
"fmt:with_os_api": "True",
},
Path: "conanfile.py",
Context: "host",
},
},
{
Name: "fmt",
Version: "9.1.0",
PURL: "pkg:conan/my_user/fmt@9.1.0?channel=my_channel",
Locations: file.NewLocationSet(file.NewLocation(fixture)),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanLockMetadataType,
Metadata: pkg.ConanLockMetadata{
Ref: "fmt/9.1.0@my_user/my_channel#6708c9d84f98d56a6d9f2e6c2d5639ba",
Options: map[string]string{
"fPIC": "True",
"header_only": "False",
"shared": "False",
"with_fmt_alias": "False",
"with_os_api": "True",
},
Path: "all/conanfile.py",
Context: "host",
},
},
Expand Down
23 changes: 16 additions & 7 deletions syft/pkg/cataloger/cpp/test-fixtures/conan.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@
"graph_lock": {
"nodes": {
"0": {
"ref": "zlib/1.2.12",
"options": "fPIC=True\nshared=False",
"requires": [],
"path": "all/conanfile.py",
"ref": "spdlog/1.11.0",
"options": "fPIC=True\nheader_only=False\nno_exceptions=False\nshared=False\nwchar_filenames=False\nwchar_support=False\nfmt:fPIC=True\nfmt:header_only=False\nfmt:shared=False\nfmt:with_fmt_alias=False\nfmt:with_os_api=True",
"requires": [
"1"
],
"path": "conanfile.py",
"context": "host"
},
"1": {
"ref": "fmt/9.1.0@my_user/my_channel#6708c9d84f98d56a6d9f2e6c2d5639ba",
"options": "fPIC=True\nheader_only=False\nshared=False\nwith_fmt_alias=False\nwith_os_api=True",
"package_id": "2c09c8f84c016041549fcee94e4caae5d89424b6",
"prev": "9f5ab13fc7c73e4a9f87e4e213f2cfa4",
"context": "host"
}
},
"revisions_enabled": false
"revisions_enabled": true
},
"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"
}
"profile_host": "[settings]\narch=x86_64\narch.march=None\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++11\ncompiler.version=11\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n"
}
6 changes: 3 additions & 3 deletions syft/pkg/cataloger/cpp/test-fixtures/conanfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
catch2/2.13.8
docopt.cpp/0.6.3
fmt/8.1.1
spdlog/1.9.2
sdl/2.0.20
fltk/1.3.8
spdlog/1.9.2@my_user/my_channel#1234567%%987654
sdl/2.0.20#1234567%%987654
fltk/1.3.8@my_user/my_channel

[generators]
cmake_find_package_multi