mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Finalize Conan v2 support (#2587)
* Add support for conan lock v2 (#2461) * conan lock 2.x requires field support Signed-off-by: houdini91 <mdstrauss91@gmail.com> * PR review, struct renaming Signed-off-by: houdini91 <mdstrauss91@gmail.com> --------- Signed-off-by: houdini91 <mdstrauss91@gmail.com> * decompose conanlock parser + add tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: houdini91 <mdstrauss91@gmail.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: mikey strauss <mdstrauss91@gmail.com>
This commit is contained in:
parent
00d6269e3c
commit
c61f59e7b7
@ -3,5 +3,5 @@ package internal
|
|||||||
const (
|
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 = "16.0.2"
|
JSONSchemaVersion = "16.0.3"
|
||||||
)
|
)
|
||||||
|
|||||||
2284
schema/json/schema-16.0.3.json
Normal file
2284
schema/json/schema-16.0.3.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "anchore.io/schema/syft/json/16.0.2/document",
|
"$id": "anchore.io/schema/syft/json/16.0.3/document",
|
||||||
"$ref": "#/$defs/Document",
|
"$ref": "#/$defs/Document",
|
||||||
"$defs": {
|
"$defs": {
|
||||||
"AlpmDbEntry": {
|
"AlpmDbEntry": {
|
||||||
@ -275,6 +275,35 @@
|
|||||||
"ref"
|
"ref"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"CConanLockV2Entry": {
|
||||||
|
"properties": {
|
||||||
|
"ref": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"packageID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"channel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"recipeRevision": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"packageRevision": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ref"
|
||||||
|
]
|
||||||
|
},
|
||||||
"CPE": {
|
"CPE": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"cpe": {
|
"cpe": {
|
||||||
@ -1363,6 +1392,9 @@
|
|||||||
{
|
{
|
||||||
"$ref": "#/$defs/CConanLockEntry"
|
"$ref": "#/$defs/CConanLockEntry"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/CConanLockV2Entry"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/CocoaPodfileLockEntry"
|
"$ref": "#/$defs/CocoaPodfileLockEntry"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,7 +11,8 @@ func AllTypes() []any {
|
|||||||
pkg.ApkDBEntry{},
|
pkg.ApkDBEntry{},
|
||||||
pkg.BinarySignature{},
|
pkg.BinarySignature{},
|
||||||
pkg.CocoaPodfileLockEntry{},
|
pkg.CocoaPodfileLockEntry{},
|
||||||
pkg.ConanLockEntry{},
|
pkg.ConanV1LockEntry{},
|
||||||
|
pkg.ConanV2LockEntry{},
|
||||||
pkg.ConanfileEntry{},
|
pkg.ConanfileEntry{},
|
||||||
pkg.ConaninfoEntry{},
|
pkg.ConaninfoEntry{},
|
||||||
pkg.DartPubspecLockEntry{},
|
pkg.DartPubspecLockEntry{},
|
||||||
|
|||||||
@ -66,7 +66,8 @@ var jsonTypes = makeJSONTypes(
|
|||||||
jsonNames(pkg.ApkDBEntry{}, "apk-db-entry", "ApkMetadata"),
|
jsonNames(pkg.ApkDBEntry{}, "apk-db-entry", "ApkMetadata"),
|
||||||
jsonNames(pkg.BinarySignature{}, "binary-signature", "BinaryMetadata"),
|
jsonNames(pkg.BinarySignature{}, "binary-signature", "BinaryMetadata"),
|
||||||
jsonNames(pkg.CocoaPodfileLockEntry{}, "cocoa-podfile-lock-entry", "CocoapodsMetadataType"),
|
jsonNames(pkg.CocoaPodfileLockEntry{}, "cocoa-podfile-lock-entry", "CocoapodsMetadataType"),
|
||||||
jsonNames(pkg.ConanLockEntry{}, "c-conan-lock-entry", "ConanLockMetadataType"),
|
jsonNames(pkg.ConanV1LockEntry{}, "c-conan-lock-entry", "ConanLockMetadataType"),
|
||||||
|
jsonNames(pkg.ConanV2LockEntry{}, "c-conan-lock-v2-entry"),
|
||||||
jsonNames(pkg.ConanfileEntry{}, "c-conan-file-entry", "ConanMetadataType"),
|
jsonNames(pkg.ConanfileEntry{}, "c-conan-file-entry", "ConanMetadataType"),
|
||||||
jsonNames(pkg.ConaninfoEntry{}, "c-conan-info-entry"),
|
jsonNames(pkg.ConaninfoEntry{}, "c-conan-info-entry"),
|
||||||
jsonNames(pkg.DartPubspecLockEntry{}, "dart-pubspec-lock-entry", "DartPubMetadata"),
|
jsonNames(pkg.DartPubspecLockEntry{}, "dart-pubspec-lock-entry", "DartPubMetadata"),
|
||||||
|
|||||||
@ -103,7 +103,7 @@ func TestReflectTypeFromJSONName_LegacyValues(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "map pkg.ConanLockEntry struct type",
|
name: "map pkg.ConanLockEntry struct type",
|
||||||
input: "ConanLockMetadataType",
|
input: "ConanLockMetadataType",
|
||||||
expected: reflect.TypeOf(pkg.ConanLockEntry{}),
|
expected: reflect.TypeOf(pkg.ConanV1LockEntry{}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "map pkg.ConanfileEntry struct type",
|
name: "map pkg.ConanfileEntry struct type",
|
||||||
@ -290,7 +290,7 @@ func Test_JSONName_JSONLegacyName(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ConanLockMetadata",
|
name: "ConanLockMetadata",
|
||||||
metadata: pkg.ConanLockEntry{},
|
metadata: pkg.ConanV1LockEntry{},
|
||||||
expectedJSONName: "c-conan-lock-entry",
|
expectedJSONName: "c-conan-lock-entry",
|
||||||
expectedLegacyName: "ConanLockMetadataType",
|
expectedLegacyName: "ConanLockMetadataType",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import (
|
|||||||
func NewConanCataloger() pkg.Cataloger {
|
func NewConanCataloger() pkg.Cataloger {
|
||||||
return generic.NewCataloger("conan-cataloger").
|
return generic.NewCataloger("conan-cataloger").
|
||||||
WithParserByGlobs(parseConanfile, "**/conanfile.txt").
|
WithParserByGlobs(parseConanfile, "**/conanfile.txt").
|
||||||
WithParserByGlobs(parseConanlock, "**/conan.lock")
|
WithParserByGlobs(parseConanLock, "**/conan.lock")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConanInfoCataloger returns a new C/C++ conaninfo.txt cataloger object.
|
// NewConanInfoCataloger returns a new C/C++ conaninfo.txt cataloger object.
|
||||||
|
|||||||
@ -70,7 +70,11 @@ func newConanfilePackage(m pkg.ConanfileEntry, locations ...file.Location) *pkg.
|
|||||||
return newConanPackage(m.Ref, m, locations...)
|
return newConanPackage(m.Ref, m, locations...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConanlockPackage(m pkg.ConanLockEntry, locations ...file.Location) *pkg.Package {
|
func newConanlockPackage(m pkg.ConanV1LockEntry, locations ...file.Location) *pkg.Package {
|
||||||
|
return newConanPackage(m.Ref, m, locations...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConanReferencePackage(m pkg.ConanV2LockEntry, locations ...file.Location) *pkg.Package {
|
||||||
return newConanPackage(m.Ref, m, locations...)
|
return newConanPackage(m.Ref, m, locations...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ generic.Parser = parseConanlock
|
var _ generic.Parser = parseConanLock
|
||||||
|
|
||||||
type conanLock struct {
|
type conanLock struct {
|
||||||
GraphLock struct {
|
GraphLock struct {
|
||||||
@ -26,13 +26,17 @@ type conanLock struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
} `json:"nodes"`
|
} `json:"nodes"`
|
||||||
} `json:"graph_lock"`
|
} `json:"graph_lock"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
ProfileHost string `json:"profile_host"`
|
ProfileHost string `json:"profile_host"`
|
||||||
|
ProfileBuild string `json:"profile_build,omitempty"`
|
||||||
|
// conan v0.5+ lockfiles use "requires", "build_requires" and "python_requires"
|
||||||
|
Requires []string `json:"requires,omitempty"`
|
||||||
|
BuildRequires []string `json:"build_requires,omitempty"`
|
||||||
|
PythonRequires []string `json:"python_requires,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseConanlock is a parser function for conan.lock contents, returning all packages discovered.
|
// parseConanLock is a parser function for conan.lock (v1 and V2) contents, returning all packages discovered.
|
||||||
func parseConanlock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
func parseConanLock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
var pkgs []pkg.Package
|
|
||||||
var cl conanLock
|
var cl conanLock
|
||||||
if err := json.NewDecoder(reader).Decode(&cl); err != nil {
|
if err := json.NewDecoder(reader).Decode(&cl); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -42,13 +46,40 @@ func parseConanlock(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
|||||||
// in a second iteration
|
// in a second iteration
|
||||||
var indexToPkgMap = map[string]pkg.Package{}
|
var indexToPkgMap = map[string]pkg.Package{}
|
||||||
|
|
||||||
|
v1Pkgs := handleConanLockV2(cl, reader, indexToPkgMap)
|
||||||
|
|
||||||
// we do not want to store the index list requires in the conan metadata, because it is not useful to have it in
|
// we do not want to store the index list requires in the conan metadata, because it is not useful to have it in
|
||||||
// the SBOM. Instead, we will store it in a map and then use it to build the relationships
|
// the SBOM. Instead, we will store it in a map and then use it to build the relationships
|
||||||
// maps pkg.ID to a list of indices
|
// maps pkg.ID to a list of indices
|
||||||
var parsedPkgRequires = map[artifact.ID][]string{}
|
var parsedPkgRequires = map[artifact.ID][]string{}
|
||||||
|
|
||||||
|
v2Pkgs := handleConanLockV1(cl, reader, parsedPkgRequires, indexToPkgMap)
|
||||||
|
|
||||||
|
var relationships []artifact.Relationship
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
pkgs = append(pkgs, v1Pkgs...)
|
||||||
|
pkgs = append(pkgs, v2Pkgs...)
|
||||||
|
|
||||||
|
for _, p := range pkgs {
|
||||||
|
requires := parsedPkgRequires[p.ID()]
|
||||||
|
for _, r := range requires {
|
||||||
|
// this is a pkg that package "p" depends on... make a relationship
|
||||||
|
relationships = append(relationships, artifact.Relationship{
|
||||||
|
From: indexToPkgMap[r],
|
||||||
|
To: p,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, relationships, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleConanLockV1 handles the parsing of conan lock v1 files (aka v0.4)
|
||||||
|
func handleConanLockV1(cl conanLock, reader file.LocationReadCloser, parsedPkgRequires map[artifact.ID][]string, indexToPkgMap map[string]pkg.Package) []pkg.Package {
|
||||||
|
var pkgs []pkg.Package
|
||||||
for idx, node := range cl.GraphLock.Nodes {
|
for idx, node := range cl.GraphLock.Nodes {
|
||||||
metadata := pkg.ConanLockEntry{
|
metadata := pkg.ConanV1LockEntry{
|
||||||
Ref: node.Ref,
|
Ref: node.Ref,
|
||||||
Options: parseOptions(node.Options),
|
Options: parseOptions(node.Options),
|
||||||
Path: node.Path,
|
Path: node.Path,
|
||||||
@ -69,22 +100,30 @@ func parseConanlock(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
|||||||
indexToPkgMap[idx] = pk
|
indexToPkgMap[idx] = pk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return pkgs
|
||||||
|
}
|
||||||
|
|
||||||
var relationships []artifact.Relationship
|
// handleConanLockV2 handles the parsing of conan lock v2 files (aka v0.5)
|
||||||
|
func handleConanLockV2(cl conanLock, reader file.LocationReadCloser, indexToPkgMap map[string]pkg.Package) []pkg.Package {
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
for _, ref := range cl.Requires {
|
||||||
|
reference, name := parseConanV2Reference(ref)
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range pkgs {
|
p := newConanReferencePackage(
|
||||||
requires := parsedPkgRequires[p.ID()]
|
reference,
|
||||||
for _, r := range requires {
|
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
// this is a pkg that package "p" depends on... make a relationship
|
)
|
||||||
relationships = append(relationships, artifact.Relationship{
|
|
||||||
From: indexToPkgMap[r],
|
if p != nil {
|
||||||
To: p,
|
pk := *p
|
||||||
Type: artifact.DependencyOfRelationship,
|
pkgs = append(pkgs, pk)
|
||||||
})
|
indexToPkgMap[name] = pk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return pkgs
|
||||||
return pkgs, relationships, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseOptions(options string) []pkg.KeyValue {
|
func parseOptions(options string) []pkg.KeyValue {
|
||||||
@ -106,3 +145,53 @@ func parseOptions(options string) []pkg.KeyValue {
|
|||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseConanV2Reference(ref string) (pkg.ConanV2LockEntry, string) {
|
||||||
|
// very flexible format name/version[@username[/channel]][#rrev][:pkgid[#prev]][%timestamp]
|
||||||
|
reference := pkg.ConanV2LockEntry{Ref: ref}
|
||||||
|
|
||||||
|
parts := strings.SplitN(ref, "%", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
ref = parts[0]
|
||||||
|
reference.TimeStamp = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = strings.SplitN(ref, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
ref = parts[0]
|
||||||
|
parts = strings.SplitN(parts[1], "#", 2)
|
||||||
|
reference.PackageID = parts[0]
|
||||||
|
if len(parts) == 2 {
|
||||||
|
reference.PackageRevision = parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = strings.SplitN(ref, "#", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
ref = parts[0]
|
||||||
|
reference.RecipeRevision = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = strings.SplitN(ref, "@", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
ref = parts[0]
|
||||||
|
UsernameChannel := parts[1]
|
||||||
|
|
||||||
|
parts = strings.SplitN(UsernameChannel, "/", 2)
|
||||||
|
reference.Username = parts[0]
|
||||||
|
if len(parts) == 2 {
|
||||||
|
reference.Channel = parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = strings.SplitN(ref, "/", 2)
|
||||||
|
var name string
|
||||||
|
if len(parts) == 2 {
|
||||||
|
name = parts[0]
|
||||||
|
} else {
|
||||||
|
// consumer conanfile.txt or conanfile.py might not have a name
|
||||||
|
name = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return reference, name
|
||||||
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseConanlock(t *testing.T) {
|
func TestParseConanLock(t *testing.T) {
|
||||||
fixture := "test-fixtures/conan.lock"
|
fixture := "test-fixtures/conan.lock"
|
||||||
expected := []pkg.Package{
|
expected := []pkg.Package{
|
||||||
{
|
{
|
||||||
@ -19,7 +19,7 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
Metadata: pkg.ConanLockEntry{
|
Metadata: pkg.ConanV1LockEntry{
|
||||||
Ref: "mfast/1.2.2@my_user/my_channel#c6f6387c9b99780f0ee05e25f99d0f39",
|
Ref: "mfast/1.2.2@my_user/my_channel#c6f6387c9b99780f0ee05e25f99d0f39",
|
||||||
Options: pkg.KeyValues{
|
Options: pkg.KeyValues{
|
||||||
{Key: "fPIC", Value: "True"},
|
{Key: "fPIC", Value: "True"},
|
||||||
@ -110,7 +110,7 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
Metadata: pkg.ConanLockEntry{
|
Metadata: pkg.ConanV1LockEntry{
|
||||||
Ref: "boost/1.75.0#a9c318f067216f900900e044e7af4ab1",
|
Ref: "boost/1.75.0#a9c318f067216f900900e044e7af4ab1",
|
||||||
Options: pkg.KeyValues{
|
Options: pkg.KeyValues{
|
||||||
{Key: "addr2line_location", Value: "/usr/bin/addr2line"},
|
{Key: "addr2line_location", Value: "/usr/bin/addr2line"},
|
||||||
@ -196,7 +196,7 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
Metadata: pkg.ConanLockEntry{
|
Metadata: pkg.ConanV1LockEntry{
|
||||||
Ref: "zlib/1.2.12#c67ce17f2e96b972d42393ce50a76a1a",
|
Ref: "zlib/1.2.12#c67ce17f2e96b972d42393ce50a76a1a",
|
||||||
Options: pkg.KeyValues{
|
Options: pkg.KeyValues{
|
||||||
{
|
{
|
||||||
@ -220,7 +220,7 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
Metadata: pkg.ConanLockEntry{
|
Metadata: pkg.ConanV1LockEntry{
|
||||||
Ref: "bzip2/1.0.8#62a8031289639043797cf53fa876d0ef",
|
Ref: "bzip2/1.0.8#62a8031289639043797cf53fa876d0ef",
|
||||||
Options: []pkg.KeyValue{
|
Options: []pkg.KeyValue{
|
||||||
{
|
{
|
||||||
@ -248,7 +248,7 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
Metadata: pkg.ConanLockEntry{
|
Metadata: pkg.ConanV1LockEntry{
|
||||||
Ref: "libbacktrace/cci.20210118#76e40b760e0bcd602d46db56b22820ab",
|
Ref: "libbacktrace/cci.20210118#76e40b760e0bcd602d46db56b22820ab",
|
||||||
Options: []pkg.KeyValue{
|
Options: []pkg.KeyValue{
|
||||||
{
|
{
|
||||||
@ -272,7 +272,7 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
Language: pkg.CPP,
|
Language: pkg.CPP,
|
||||||
Type: pkg.ConanPkg,
|
Type: pkg.ConanPkg,
|
||||||
Metadata: pkg.ConanLockEntry{
|
Metadata: pkg.ConanV1LockEntry{
|
||||||
Ref: "tinyxml2/9.0.0#9f13a36ebfc222cd55fe531a0a8d94d1",
|
Ref: "tinyxml2/9.0.0#9f13a36ebfc222cd55fe531a0a8d94d1",
|
||||||
Options: []pkg.KeyValue{
|
Options: []pkg.KeyValue{
|
||||||
{
|
{
|
||||||
@ -330,5 +330,46 @@ func TestParseConanlock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgtest.TestFileParser(t, fixture, parseConanlock, expected, expectedRelationships)
|
pkgtest.TestFileParser(t, fixture, parseConanLock, expected, expectedRelationships)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseConanLockV2(t *testing.T) {
|
||||||
|
fixture := "test-fixtures/conanlock-v2/conan.lock"
|
||||||
|
expected := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "matrix",
|
||||||
|
Version: "1.1",
|
||||||
|
PURL: "pkg:conan/matrix@1.1",
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
|
Language: pkg.CPP,
|
||||||
|
Type: pkg.ConanPkg,
|
||||||
|
Metadata: pkg.ConanV2LockEntry{
|
||||||
|
Ref: "matrix/1.1#905c3f0babc520684c84127378fefdd0%1675278901.7527816",
|
||||||
|
RecipeRevision: "905c3f0babc520684c84127378fefdd0",
|
||||||
|
TimeStamp: "1675278901.7527816",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "sound32",
|
||||||
|
Version: "1.0",
|
||||||
|
PURL: "pkg:conan/sound32@1.0",
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation(fixture)),
|
||||||
|
Language: pkg.CPP,
|
||||||
|
Type: pkg.ConanPkg,
|
||||||
|
Metadata: pkg.ConanV2LockEntry{
|
||||||
|
Ref: "sound32/1.0#83d4b7bf607b3b60a6546f8b58b5cdd7%1675278904.0791488",
|
||||||
|
RecipeRevision: "83d4b7bf607b3b60a6546f8b58b5cdd7",
|
||||||
|
TimeStamp: "1675278904.0791488",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// relationships require IDs to be set to be sorted similarly
|
||||||
|
for i := range expected {
|
||||||
|
expected[i].SetID()
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedRelationships []artifact.Relationship
|
||||||
|
|
||||||
|
pkgtest.TestFileParser(t, fixture, parseConanLock, expected, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": "0.5",
|
||||||
|
"requires": [
|
||||||
|
"sound32/1.0#83d4b7bf607b3b60a6546f8b58b5cdd7%1675278904.0791488",
|
||||||
|
"matrix/1.1#905c3f0babc520684c84127378fefdd0%1675278901.7527816"
|
||||||
|
],
|
||||||
|
"build_requires": [],
|
||||||
|
"python_requires": []
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
// ConanLockEntry represents a single "node" entry from a conan.lock file.
|
// ConanV1LockEntry represents a single "node" entry from a conan.lock V1 file.
|
||||||
type ConanLockEntry struct {
|
type ConanV1LockEntry struct {
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
PackageID string `json:"package_id,omitempty"`
|
PackageID string `json:"package_id,omitempty"`
|
||||||
Prev string `json:"prev,omitempty"`
|
Prev string `json:"prev,omitempty"`
|
||||||
@ -13,6 +13,17 @@ type ConanLockEntry struct {
|
|||||||
Context string `json:"context,omitempty"`
|
Context string `json:"context,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConanV2LockEntry represents a single "node" entry from a conan.lock V2 file.
|
||||||
|
type ConanV2LockEntry struct {
|
||||||
|
Ref string `json:"ref"`
|
||||||
|
PackageID string `json:"packageID,omitempty"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Channel string `json:"channel,omitempty"`
|
||||||
|
RecipeRevision string `json:"recipeRevision,omitempty"`
|
||||||
|
PackageRevision string `json:"packageRevision,omitempty"`
|
||||||
|
TimeStamp string `json:"timestamp,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// ConanfileEntry represents a single "Requires" entry from a conanfile.txt.
|
// ConanfileEntry represents a single "Requires" entry from a conanfile.txt.
|
||||||
type ConanfileEntry struct {
|
type ConanfileEntry struct {
|
||||||
Ref string `mapstructure:"ref" json:"ref"`
|
Ref string `mapstructure:"ref" json:"ref"`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user