From f98868b55e422e5b9829adc97d3063ec90a39573 Mon Sep 17 00:00:00 2001 From: Dan Luhring Date: Mon, 13 Dec 2021 15:39:42 -0500 Subject: [PATCH] Find Java package versions in additional manifest sections (#673) * Add failing test for missing versions Signed-off-by: Dan Luhring * Look through all named sections for version Signed-off-by: Dan Luhring * Consistent installation of yajsv Signed-off-by: Dan Luhring * Adjust output text for test assertion Signed-off-by: Dan Luhring --- Makefile | 3 +- schema/cyclonedx/Makefile | 2 +- .../pkg/cataloger/java/parse_java_manifest.go | 45 ++++++++--- .../java/parse_java_manifest_test.go | 77 ++++++++++++++++++- test/cli/packages_cmd_test.go | 2 +- 5 files changed, 114 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 0923efc84..c5b8abf17 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ help: .PHONY: ci-bootstrap ci-bootstrap: - DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils && go install github.com/neilpa/yajsv@latest + DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils .PHONY: ci-bootstrap-mac: @@ -101,6 +101,7 @@ bootstrap-tools: $(TEMPDIR) curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.2.0 curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0 .github/scripts/goreleaser-install.sh -b $(TEMPDIR)/ v0.177.0 + GOBIN="$(shell realpath $(TEMPDIR))" go install github.com/neilpa/yajsv@v1.4.0 .PHONY: bootstrap-go bootstrap-go: diff --git a/schema/cyclonedx/Makefile b/schema/cyclonedx/Makefile index 38fa40bd2..d65c14678 100644 --- a/schema/cyclonedx/Makefile +++ b/schema/cyclonedx/Makefile @@ -4,4 +4,4 @@ validate-schema: go run ../../main.go ubuntu:latest -vv -o cyclonedx > bom.xml xmllint --noout --schema ./cyclonedx.xsd bom.xml go run ../../main.go ubuntu:latest -vv -o cyclonedx-json > bom.json - yajsv -s bom-1.3.schema.json bom.json + ../../.tmp/yajsv -s bom-1.3.schema.json bom.json diff --git a/syft/pkg/cataloger/java/parse_java_manifest.go b/syft/pkg/cataloger/java/parse_java_manifest.go index ba44aec58..bca439963 100644 --- a/syft/pkg/cataloger/java/parse_java_manifest.go +++ b/syft/pkg/cataloger/java/parse_java_manifest.go @@ -115,16 +115,39 @@ func selectName(manifest *pkg.JavaManifest, filenameObj archiveFilename) string } func selectVersion(manifest *pkg.JavaManifest, filenameObj archiveFilename) string { - var version string - switch { - case filenameObj.version != "": - version = filenameObj.version - case manifest.Main["Implementation-Version"] != "": - version = manifest.Main["Implementation-Version"] - case manifest.Main["Specification-Version"] != "": - version = manifest.Main["Specification-Version"] - case manifest.Main["Plugin-Version"] != "": - version = manifest.Main["Plugin-Version"] + if v := filenameObj.version; v != "" { + return v } - return version + + if manifest == nil { + return "" + } + + fieldNames := []string{ + "Implementation-Version", + "Specification-Version", + "Plugin-Version", + } + + for _, fieldName := range fieldNames { + if v := fieldValueFromManifest(*manifest, fieldName); v != "" { + return v + } + } + + return "" +} + +func fieldValueFromManifest(manifest pkg.JavaManifest, fieldName string) string { + if value := manifest.Main[fieldName]; value != "" { + return value + } + + for _, section := range manifest.NamedSections { + if value := section[fieldName]; value != "" { + return value + } + } + + return "" } diff --git a/syft/pkg/cataloger/java/parse_java_manifest_test.go b/syft/pkg/cataloger/java/parse_java_manifest_test.go index d80a864fa..e044b8358 100644 --- a/syft/pkg/cataloger/java/parse_java_manifest_test.go +++ b/syft/pkg/cataloger/java/parse_java_manifest_test.go @@ -5,6 +5,8 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" + "github.com/anchore/syft/syft/pkg" "github.com/go-test/deep" ) @@ -145,5 +147,78 @@ func TestSelectName(t *testing.T) { } }) } - +} + +func TestSelectVersion(t *testing.T) { + tests := []struct { + name string + manifest pkg.JavaManifest + archive archiveFilename + expected string + }{ + { + name: "Get name from Implementation-Version", + archive: archiveFilename{}, + manifest: pkg.JavaManifest{ + Main: map[string]string{ + "Implementation-Version": "1.8.2", + }, + }, + expected: "1.8.2", + }, + { + name: "Implementation-Version takes precedence over Specification-Version", + manifest: pkg.JavaManifest{ + Main: map[string]string{ + "Implementation-Version": "1.8.2", + "Specification-Version": "1.0", + }, + }, + expected: "1.8.2", + }, + { + name: "Implementation-Version found outside the main section", + manifest: pkg.JavaManifest{ + Main: map[string]string{ + "Manifest-Version": "1.0", + "Ant-Version": "Apache Ant 1.8.2", + "Created-By": "1.5.0_22-b03 (Sun Microsystems Inc.)", + }, + NamedSections: map[string]map[string]string{ + "org/apache/tools/ant/taskdefs/optional/": { + "Implementation-Version": "1.8.2", + }, + }, + }, + expected: "1.8.2", + }, + { + name: "Implementation-Version takes precedence over Specification-Version in subsequent section", + manifest: pkg.JavaManifest{ + Main: map[string]string{ + "Manifest-Version": "1.0", + "Ant-Version": "Apache Ant 1.8.2", + "Created-By": "1.5.0_22-b03 (Sun Microsystems Inc.)", + "Specification-Version": "2.0", + }, + NamedSections: map[string]map[string]string{ + "org/apache/tools/ant/taskdefs/optional/": { + "Specification-Version": "1.8", + }, + "some-other-section": { + "Implementation-Version": "1.8.2", + }, + }, + }, + expected: "1.8.2", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := selectVersion(&test.manifest, test.archive) + + assert.Equal(t, test.expected, result) + }) + } } diff --git a/test/cli/packages_cmd_test.go b/test/cli/packages_cmd_test.go index 757142d04..cf1520135 100644 --- a/test/cli/packages_cmd_test.go +++ b/test/cli/packages_cmd_test.go @@ -42,7 +42,7 @@ func TestPackagesCmdFlags(t *testing.T) { // a CLI test is much easier. args: []string{"packages", "-vv", badBinariesImage}, assertions: []traitAssertion{ - assertInOutput("recovered from panic while parse go binary"), + assertInOutput("could not parse possible go binary"), assertSuccessfulReturnCode, }, },