mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
fix: #953 Derive language from pURL - https://github.com/anchore/syft… (#957)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
This commit is contained in:
parent
c270ee2a02
commit
7304bbf8ee
@ -86,6 +86,10 @@ func decodeComponent(c *cyclonedx.Component) *pkg.Package {
|
|||||||
p.Type = pkg.TypeFromPURL(p.PURL)
|
p.Type = pkg.TypeFromPURL(p.PURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.Language == "" {
|
||||||
|
p.Language = pkg.LanguageFromPURL(p.PURL)
|
||||||
|
}
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -191,3 +191,31 @@ func Test_deriveBomRef(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_decodeComponent(t *testing.T) {
|
||||||
|
javaComponentWithNoSyftProperties := cyclonedx.Component{
|
||||||
|
Name: "ch.qos.logback/logback-classic",
|
||||||
|
Version: "1.2.3",
|
||||||
|
PackageURL: "pkg:maven/ch.qos.logback/logback-classic@1.2.3",
|
||||||
|
Type: "library",
|
||||||
|
BOMRef: "pkg:maven/ch.qos.logback/logback-classic@1.2.3",
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
component cyclonedx.Component
|
||||||
|
want pkg.Language
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "derive language from pURL if missing",
|
||||||
|
component: javaComponentWithNoSyftProperties,
|
||||||
|
want: pkg.Java,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.want, decodeComponent(&tt.component).Language)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -70,6 +70,13 @@ func Catalog(resolver source.FileResolver, release *linux.Release, catalogers ..
|
|||||||
// generate PURL (note: this is excluded from package ID, so is safe to mutate)
|
// generate PURL (note: this is excluded from package ID, so is safe to mutate)
|
||||||
p.PURL = pkg.URL(p, release)
|
p.PURL = pkg.URL(p, release)
|
||||||
|
|
||||||
|
// if we were not able to identify the language we have an opportunity
|
||||||
|
// to try and get this value from the PURL. Worst case we assert that
|
||||||
|
// we could not identify the language at either stage and set UnknownLanguage
|
||||||
|
if p.Language == "" {
|
||||||
|
p.Language = pkg.LanguageFromPURL(p.PURL)
|
||||||
|
}
|
||||||
|
|
||||||
// create file-to-package relationships for files owned by the package
|
// create file-to-package relationships for files owned by the package
|
||||||
owningRelationships, err := packageFileOwnershipRelationships(p, resolver)
|
owningRelationships, err := packageFileOwnershipRelationships(p, resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ type Language string
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// the full set of supported programming languages
|
// the full set of supported programming languages
|
||||||
UnknownLanguage Language = "UnknownLanguage"
|
UnknownLanguage Language = ""
|
||||||
Java Language = "java"
|
Java Language = "java"
|
||||||
JavaScript Language = "javascript"
|
JavaScript Language = "javascript"
|
||||||
Python Language = "python"
|
Python Language = "python"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/anchore/syft/internal/formats/cyclonedxxml"
|
"github.com/anchore/syft/internal/formats/cyclonedxxml"
|
||||||
"github.com/anchore/syft/internal/formats/syftjson"
|
"github.com/anchore/syft/internal/formats/syftjson"
|
||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -21,12 +22,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// TestEncodeDecodeEncodeCycleComparison is testing for differences in how SBOM documents get encoded on multiple cycles.
|
// TestEncodeDecodeEncodeCycleComparison is testing for differences in how SBOM documents get encoded on multiple cycles.
|
||||||
// By encding and decoding the sbom we can compare the differences between the set of resulting objects. However,
|
// By encoding and decoding the sbom we can compare the differences between the set of resulting objects. However,
|
||||||
// this requires specific comparisons being done, and select redactions/omissions being made. Additionally, there are
|
// this requires specific comparisons being done, and select redactions/omissions being made. Additionally, there are
|
||||||
// already unit tests on each format encoder-decoder for properly functioning comparisons in depth, so there is no need
|
// already unit tests on each format encoder-decoder for properly functioning comparisons in depth, so there is no need
|
||||||
// to do an object-to-object comparison. For this reason this test focuses on a bytes-to-bytes comparison after an
|
// to do an object-to-object comparison. For this reason this test focuses on a bytes-to-bytes comparison after an
|
||||||
// encode-decode-encode loop which will detect lossy behavior in both directions.
|
// encode-decode-encode loop which will detect lossy behavior in both directions.
|
||||||
func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
||||||
|
// use second image for relationships
|
||||||
|
images := []string{"image-pkg-coverage", "image-owning-package"}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
formatOption sbom.FormatID
|
formatOption sbom.FormatID
|
||||||
redactor func(in []byte) []byte
|
redactor func(in []byte) []byte
|
||||||
@ -34,6 +37,10 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
formatOption: syftjson.ID,
|
formatOption: syftjson.ID,
|
||||||
|
redactor: func(in []byte) []byte {
|
||||||
|
in = regexp.MustCompile("\"(id|parent)\": \"[^\"]+\",").ReplaceAll(in, []byte{})
|
||||||
|
return in
|
||||||
|
},
|
||||||
json: true,
|
json: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -55,9 +62,8 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
// use second image for relationships
|
t.Run(fmt.Sprintf("%s", test.formatOption), func(t *testing.T) {
|
||||||
for _, image := range []string{"image-pkg-coverage", "image-owning-package"} {
|
for _, image := range images {
|
||||||
t.Run(fmt.Sprintf("%s/%s", test.formatOption, image), func(t *testing.T) {
|
|
||||||
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope)
|
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope)
|
||||||
|
|
||||||
format := syft.FormatByID(test.formatOption)
|
format := syft.FormatByID(test.formatOption)
|
||||||
@ -81,9 +87,10 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
|||||||
if test.json {
|
if test.json {
|
||||||
s1 := string(by1)
|
s1 := string(by1)
|
||||||
s2 := string(by2)
|
s2 := string(by2)
|
||||||
assert.JSONEq(t, s1, s2)
|
if diff := cmp.Diff(s1, s2); diff != "" {
|
||||||
} else {
|
t.Errorf("Encode/Decode mismatch (-want +got):\n%s", diff)
|
||||||
if !assert.True(t, bytes.Equal(by1, by2)) {
|
}
|
||||||
|
} else if !assert.True(t, bytes.Equal(by1, by2)) {
|
||||||
dmp := diffmatchpatch.New()
|
dmp := diffmatchpatch.New()
|
||||||
diffs := dmp.DiffMain(string(by1), string(by2), true)
|
diffs := dmp.DiffMain(string(by1), string(by2), true)
|
||||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||||
@ -92,4 +99,3 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user