mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
translate maps to sequences in pkg metadata (#2553)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
fef0e54c0f
commit
6107e5e2ad
@ -3,5 +3,5 @@ package internal
|
||||
const (
|
||||
// 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.
|
||||
JSONSchemaVersion = "14.0.0"
|
||||
JSONSchemaVersion = "15.0.0"
|
||||
)
|
||||
|
||||
2147
schema/json/schema-15.0.0.json
Normal file
2147
schema/json/schema-15.0.0.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -68,6 +68,10 @@ func findMetadataDefinitionNames(paths ...string) ([]string, error) {
|
||||
// any definition that is used within another struct should not be considered a top-level metadata definition
|
||||
names.Remove(usedNames.List()...)
|
||||
|
||||
// remove known exceptions, that is, types exported in the pkg Package that are not used
|
||||
// in a metadata type but are not metadata types themselves.
|
||||
names.Remove("Licenses", "KeyValue")
|
||||
|
||||
strNames := names.List()
|
||||
sort.Strings(strNames)
|
||||
|
||||
@ -114,7 +118,11 @@ func findMetadataDefinitionNamesInFile(path string) ([]string, []string, error)
|
||||
|
||||
structType := extractStructType(spec.Type)
|
||||
if structType == nil {
|
||||
continue
|
||||
// maybe this is a slice of structs? This is useful (say type KeyValues is []KeyValue)
|
||||
structType = extractSliceOfStructType(spec.Type)
|
||||
if structType == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
metadataDefinitions = append(metadataDefinitions, name)
|
||||
@ -124,6 +132,34 @@ func findMetadataDefinitionNamesInFile(path string) ([]string, []string, error)
|
||||
return metadataDefinitions, usedTypeNames, nil
|
||||
}
|
||||
|
||||
func extractSliceOfStructType(exp ast.Expr) *ast.StructType {
|
||||
var structType *ast.StructType
|
||||
switch ty := exp.(type) {
|
||||
case *ast.ArrayType:
|
||||
// this is a standard definition:
|
||||
// type FooMetadata []BarMetadata
|
||||
structType = extractStructType(ty.Elt)
|
||||
case *ast.Ident:
|
||||
if ty.Obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// this might be a type created from another type:
|
||||
// type FooMetadata BarMetadata
|
||||
// ... but we need to check that the other type definition is a struct type
|
||||
typeSpec, ok := ty.Obj.Decl.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
nestedStructType, ok := typeSpec.Type.(*ast.StructType)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
structType = nestedStructType
|
||||
}
|
||||
return structType
|
||||
}
|
||||
|
||||
func extractStructType(exp ast.Expr) *ast.StructType {
|
||||
var structType *ast.StructType
|
||||
switch ty := exp.(type) {
|
||||
|
||||
@ -87,8 +87,8 @@ func parseConanlock(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
||||
return pkgs, relationships, nil
|
||||
}
|
||||
|
||||
func parseOptions(options string) map[string]string {
|
||||
o := make(map[string]string)
|
||||
func parseOptions(options string) []pkg.KeyValue {
|
||||
o := make([]pkg.KeyValue, 0)
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -97,7 +97,10 @@ func parseOptions(options string) map[string]string {
|
||||
for _, kvp := range kvps {
|
||||
kv := strings.Split(kvp, "=")
|
||||
if len(kv) == 2 {
|
||||
o[kv[0]] = kv[1]
|
||||
o = append(o, pkg.KeyValue{
|
||||
Key: kv[0],
|
||||
Value: kv[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,82 +21,82 @@ func TestParseConanlock(t *testing.T) {
|
||||
Type: pkg.ConanPkg,
|
||||
Metadata: pkg.ConanLockEntry{
|
||||
Ref: "mfast/1.2.2@my_user/my_channel#c6f6387c9b99780f0ee05e25f99d0f39",
|
||||
Options: map[string]string{
|
||||
"fPIC": "True",
|
||||
"shared": "False",
|
||||
"with_sqlite3": "False",
|
||||
"boost:addr2line_location": "/usr/bin/addr2line",
|
||||
"boost:asio_no_deprecated": "False",
|
||||
"boost:buildid": "None",
|
||||
"boost:bzip2": "True",
|
||||
"boost:debug_level": "0",
|
||||
"boost:diagnostic_definitions": "False",
|
||||
"boost:error_code_header_only": "False",
|
||||
"boost:extra_b2_flags": "None",
|
||||
"boost:fPIC": "True",
|
||||
"boost:filesystem_no_deprecated": "False",
|
||||
"boost:header_only": "False",
|
||||
"boost:i18n_backend": "deprecated",
|
||||
"boost:i18n_backend_iconv": "libc",
|
||||
"boost:i18n_backend_icu": "False",
|
||||
"boost:layout": "system",
|
||||
"boost:lzma": "False",
|
||||
"boost:magic_autolink": "False",
|
||||
"boost:multithreading": "True",
|
||||
"boost:namespace": "boost",
|
||||
"boost:namespace_alias": "False",
|
||||
"boost:numa": "True",
|
||||
"boost:pch": "True",
|
||||
"boost:python_executable": "None",
|
||||
"boost:python_version": "None",
|
||||
"boost:segmented_stacks": "False",
|
||||
"boost:shared": "False",
|
||||
"boost:system_no_deprecated": "False",
|
||||
"boost:system_use_utf8": "False",
|
||||
"boost:visibility": "hidden",
|
||||
"boost:with_stacktrace_backtrace": "True",
|
||||
"boost:without_atomic": "False",
|
||||
"boost:without_chrono": "False",
|
||||
"boost:without_container": "False",
|
||||
"boost:without_context": "False",
|
||||
"boost:without_contract": "False",
|
||||
"boost:without_coroutine": "False",
|
||||
"boost:without_date_time": "False",
|
||||
"boost:without_exception": "False",
|
||||
"boost:without_fiber": "False",
|
||||
"boost:without_filesystem": "False",
|
||||
"boost:without_graph": "False",
|
||||
"boost:without_graph_parallel": "True",
|
||||
"boost:without_iostreams": "False",
|
||||
"boost:without_json": "False",
|
||||
"boost:without_locale": "False",
|
||||
"boost:without_log": "False",
|
||||
"boost:without_math": "False",
|
||||
"boost:without_mpi": "True",
|
||||
"boost:without_nowide": "False",
|
||||
"boost:without_program_options": "False",
|
||||
"boost:without_python": "True",
|
||||
"boost:without_random": "False",
|
||||
"boost:without_regex": "False",
|
||||
"boost:without_serialization": "False",
|
||||
"boost:without_stacktrace": "False",
|
||||
"boost:without_system": "False",
|
||||
"boost:without_test": "False",
|
||||
"boost:without_thread": "False",
|
||||
"boost:without_timer": "False",
|
||||
"boost:without_type_erasure": "False",
|
||||
"boost:without_wave": "False",
|
||||
"boost:zlib": "True",
|
||||
"boost:zstd": "False",
|
||||
"bzip2:build_executable": "True",
|
||||
"bzip2:fPIC": "True",
|
||||
"bzip2:shared": "False",
|
||||
"libbacktrace:fPIC": "True",
|
||||
"libbacktrace:shared": "False",
|
||||
"tinyxml2:fPIC": "True",
|
||||
"tinyxml2:shared": "False",
|
||||
"zlib:fPIC": "True",
|
||||
"zlib:shared": "False",
|
||||
Options: pkg.KeyValues{
|
||||
{Key: "fPIC", Value: "True"},
|
||||
{Key: "shared", Value: "False"},
|
||||
{Key: "with_sqlite3", Value: "False"},
|
||||
{Key: "boost:addr2line_location", Value: "/usr/bin/addr2line"},
|
||||
{Key: "boost:asio_no_deprecated", Value: "False"},
|
||||
{Key: "boost:buildid", Value: "None"},
|
||||
{Key: "boost:bzip2", Value: "True"},
|
||||
{Key: "boost:debug_level", Value: "0"},
|
||||
{Key: "boost:diagnostic_definitions", Value: "False"},
|
||||
{Key: "boost:error_code_header_only", Value: "False"},
|
||||
{Key: "boost:extra_b2_flags", Value: "None"},
|
||||
{Key: "boost:fPIC", Value: "True"},
|
||||
{Key: "boost:filesystem_no_deprecated", Value: "False"},
|
||||
{Key: "boost:header_only", Value: "False"},
|
||||
{Key: "boost:i18n_backend", Value: "deprecated"},
|
||||
{Key: "boost:i18n_backend_iconv", Value: "libc"},
|
||||
{Key: "boost:i18n_backend_icu", Value: "False"},
|
||||
{Key: "boost:layout", Value: "system"},
|
||||
{Key: "boost:lzma", Value: "False"},
|
||||
{Key: "boost:magic_autolink", Value: "False"},
|
||||
{Key: "boost:multithreading", Value: "True"},
|
||||
{Key: "boost:namespace", Value: "boost"},
|
||||
{Key: "boost:namespace_alias", Value: "False"},
|
||||
{Key: "boost:numa", Value: "True"},
|
||||
{Key: "boost:pch", Value: "True"},
|
||||
{Key: "boost:python_executable", Value: "None"},
|
||||
{Key: "boost:python_version", Value: "None"},
|
||||
{Key: "boost:segmented_stacks", Value: "False"},
|
||||
{Key: "boost:shared", Value: "False"},
|
||||
{Key: "boost:system_no_deprecated", Value: "False"},
|
||||
{Key: "boost:system_use_utf8", Value: "False"},
|
||||
{Key: "boost:visibility", Value: "hidden"},
|
||||
{Key: "boost:with_stacktrace_backtrace", Value: "True"},
|
||||
{Key: "boost:without_atomic", Value: "False"},
|
||||
{Key: "boost:without_chrono", Value: "False"},
|
||||
{Key: "boost:without_container", Value: "False"},
|
||||
{Key: "boost:without_context", Value: "False"},
|
||||
{Key: "boost:without_contract", Value: "False"},
|
||||
{Key: "boost:without_coroutine", Value: "False"},
|
||||
{Key: "boost:without_date_time", Value: "False"},
|
||||
{Key: "boost:without_exception", Value: "False"},
|
||||
{Key: "boost:without_fiber", Value: "False"},
|
||||
{Key: "boost:without_filesystem", Value: "False"},
|
||||
{Key: "boost:without_graph", Value: "False"},
|
||||
{Key: "boost:without_graph_parallel", Value: "True"},
|
||||
{Key: "boost:without_iostreams", Value: "False"},
|
||||
{Key: "boost:without_json", Value: "False"},
|
||||
{Key: "boost:without_locale", Value: "False"},
|
||||
{Key: "boost:without_log", Value: "False"},
|
||||
{Key: "boost:without_math", Value: "False"},
|
||||
{Key: "boost:without_mpi", Value: "True"},
|
||||
{Key: "boost:without_nowide", Value: "False"},
|
||||
{Key: "boost:without_program_options", Value: "False"},
|
||||
{Key: "boost:without_python", Value: "True"},
|
||||
{Key: "boost:without_random", Value: "False"},
|
||||
{Key: "boost:without_regex", Value: "False"},
|
||||
{Key: "boost:without_serialization", Value: "False"},
|
||||
{Key: "boost:without_stacktrace", Value: "False"},
|
||||
{Key: "boost:without_system", Value: "False"},
|
||||
{Key: "boost:without_test", Value: "False"},
|
||||
{Key: "boost:without_thread", Value: "False"},
|
||||
{Key: "boost:without_timer", Value: "False"},
|
||||
{Key: "boost:without_type_erasure", Value: "False"},
|
||||
{Key: "boost:without_wave", Value: "False"},
|
||||
{Key: "boost:zlib", Value: "True"},
|
||||
{Key: "boost:zstd", Value: "False"},
|
||||
{Key: "bzip2:build_executable", Value: "True"},
|
||||
{Key: "bzip2:fPIC", Value: "True"},
|
||||
{Key: "bzip2:shared", Value: "False"},
|
||||
{Key: "libbacktrace:fPIC", Value: "True"},
|
||||
{Key: "libbacktrace:shared", Value: "False"},
|
||||
{Key: "tinyxml2:fPIC", Value: "True"},
|
||||
{Key: "tinyxml2:shared", Value: "False"},
|
||||
{Key: "zlib:fPIC", Value: "True"},
|
||||
{Key: "zlib:shared", Value: "False"},
|
||||
},
|
||||
Context: "host",
|
||||
PackageID: "9d1f076b471417647c2022a78d5e2c1f834289ac",
|
||||
@ -112,77 +112,77 @@ func TestParseConanlock(t *testing.T) {
|
||||
Type: pkg.ConanPkg,
|
||||
Metadata: pkg.ConanLockEntry{
|
||||
Ref: "boost/1.75.0#a9c318f067216f900900e044e7af4ab1",
|
||||
Options: map[string]string{
|
||||
"addr2line_location": "/usr/bin/addr2line",
|
||||
"asio_no_deprecated": "False",
|
||||
"buildid": "None",
|
||||
"bzip2": "True",
|
||||
"debug_level": "0",
|
||||
"diagnostic_definitions": "False",
|
||||
"error_code_header_only": "False",
|
||||
"extra_b2_flags": "None",
|
||||
"fPIC": "True",
|
||||
"filesystem_no_deprecated": "False",
|
||||
"header_only": "False",
|
||||
"i18n_backend": "deprecated",
|
||||
"i18n_backend_iconv": "libc",
|
||||
"i18n_backend_icu": "False",
|
||||
"layout": "system",
|
||||
"lzma": "False",
|
||||
"magic_autolink": "False",
|
||||
"multithreading": "True",
|
||||
"namespace": "boost",
|
||||
"namespace_alias": "False",
|
||||
"numa": "True",
|
||||
"pch": "True",
|
||||
"python_executable": "None",
|
||||
"python_version": "None",
|
||||
"segmented_stacks": "False",
|
||||
"shared": "False",
|
||||
"system_no_deprecated": "False",
|
||||
"system_use_utf8": "False",
|
||||
"visibility": "hidden",
|
||||
"with_stacktrace_backtrace": "True",
|
||||
"without_atomic": "False",
|
||||
"without_chrono": "False",
|
||||
"without_container": "False",
|
||||
"without_context": "False",
|
||||
"without_contract": "False",
|
||||
"without_coroutine": "False",
|
||||
"without_date_time": "False",
|
||||
"without_exception": "False",
|
||||
"without_fiber": "False",
|
||||
"without_filesystem": "False",
|
||||
"without_graph": "False",
|
||||
"without_graph_parallel": "True",
|
||||
"without_iostreams": "False",
|
||||
"without_json": "False",
|
||||
"without_locale": "False",
|
||||
"without_log": "False",
|
||||
"without_math": "False",
|
||||
"without_mpi": "True",
|
||||
"without_nowide": "False",
|
||||
"without_program_options": "False",
|
||||
"without_python": "True",
|
||||
"without_random": "False",
|
||||
"without_regex": "False",
|
||||
"without_serialization": "False",
|
||||
"without_stacktrace": "False",
|
||||
"without_system": "False",
|
||||
"without_test": "False",
|
||||
"without_thread": "False",
|
||||
"without_timer": "False",
|
||||
"without_type_erasure": "False",
|
||||
"without_wave": "False",
|
||||
"zlib": "True",
|
||||
"zstd": "False",
|
||||
"bzip2:build_executable": "True",
|
||||
"bzip2:fPIC": "True",
|
||||
"bzip2:shared": "False",
|
||||
"libbacktrace:fPIC": "True",
|
||||
"libbacktrace:shared": "False",
|
||||
"zlib:fPIC": "True",
|
||||
"zlib:shared": "False",
|
||||
Options: pkg.KeyValues{
|
||||
{Key: "addr2line_location", Value: "/usr/bin/addr2line"},
|
||||
{Key: "asio_no_deprecated", Value: "False"},
|
||||
{Key: "buildid", Value: "None"},
|
||||
{Key: "bzip2", Value: "True"},
|
||||
{Key: "debug_level", Value: "0"},
|
||||
{Key: "diagnostic_definitions", Value: "False"},
|
||||
{Key: "error_code_header_only", Value: "False"},
|
||||
{Key: "extra_b2_flags", Value: "None"},
|
||||
{Key: "fPIC", Value: "True"},
|
||||
{Key: "filesystem_no_deprecated", Value: "False"},
|
||||
{Key: "header_only", Value: "False"},
|
||||
{Key: "i18n_backend", Value: "deprecated"},
|
||||
{Key: "i18n_backend_iconv", Value: "libc"},
|
||||
{Key: "i18n_backend_icu", Value: "False"},
|
||||
{Key: "layout", Value: "system"},
|
||||
{Key: "lzma", Value: "False"},
|
||||
{Key: "magic_autolink", Value: "False"},
|
||||
{Key: "multithreading", Value: "True"},
|
||||
{Key: "namespace", Value: "boost"},
|
||||
{Key: "namespace_alias", Value: "False"},
|
||||
{Key: "numa", Value: "True"},
|
||||
{Key: "pch", Value: "True"},
|
||||
{Key: "python_executable", Value: "None"},
|
||||
{Key: "python_version", Value: "None"},
|
||||
{Key: "segmented_stacks", Value: "False"},
|
||||
{Key: "shared", Value: "False"},
|
||||
{Key: "system_no_deprecated", Value: "False"},
|
||||
{Key: "system_use_utf8", Value: "False"},
|
||||
{Key: "visibility", Value: "hidden"},
|
||||
{Key: "with_stacktrace_backtrace", Value: "True"},
|
||||
{Key: "without_atomic", Value: "False"},
|
||||
{Key: "without_chrono", Value: "False"},
|
||||
{Key: "without_container", Value: "False"},
|
||||
{Key: "without_context", Value: "False"},
|
||||
{Key: "without_contract", Value: "False"},
|
||||
{Key: "without_coroutine", Value: "False"},
|
||||
{Key: "without_date_time", Value: "False"},
|
||||
{Key: "without_exception", Value: "False"},
|
||||
{Key: "without_fiber", Value: "False"},
|
||||
{Key: "without_filesystem", Value: "False"},
|
||||
{Key: "without_graph", Value: "False"},
|
||||
{Key: "without_graph_parallel", Value: "True"},
|
||||
{Key: "without_iostreams", Value: "False"},
|
||||
{Key: "without_json", Value: "False"},
|
||||
{Key: "without_locale", Value: "False"},
|
||||
{Key: "without_log", Value: "False"},
|
||||
{Key: "without_math", Value: "False"},
|
||||
{Key: "without_mpi", Value: "True"},
|
||||
{Key: "without_nowide", Value: "False"},
|
||||
{Key: "without_program_options", Value: "False"},
|
||||
{Key: "without_python", Value: "True"},
|
||||
{Key: "without_random", Value: "False"},
|
||||
{Key: "without_regex", Value: "False"},
|
||||
{Key: "without_serialization", Value: "False"},
|
||||
{Key: "without_stacktrace", Value: "False"},
|
||||
{Key: "without_system", Value: "False"},
|
||||
{Key: "without_test", Value: "False"},
|
||||
{Key: "without_thread", Value: "False"},
|
||||
{Key: "without_timer", Value: "False"},
|
||||
{Key: "without_type_erasure", Value: "False"},
|
||||
{Key: "without_wave", Value: "False"},
|
||||
{Key: "zlib", Value: "True"},
|
||||
{Key: "zstd", Value: "False"},
|
||||
{Key: "bzip2:build_executable", Value: "True"},
|
||||
{Key: "bzip2:fPIC", Value: "True"},
|
||||
{Key: "bzip2:shared", Value: "False"},
|
||||
{Key: "libbacktrace:fPIC", Value: "True"},
|
||||
{Key: "libbacktrace:shared", Value: "False"},
|
||||
{Key: "zlib:fPIC", Value: "True"},
|
||||
{Key: "zlib:shared", Value: "False"},
|
||||
},
|
||||
Context: "host",
|
||||
PackageID: "dc8aedd23a0f0a773a5fcdcfe1ae3e89c4205978",
|
||||
@ -198,9 +198,15 @@ func TestParseConanlock(t *testing.T) {
|
||||
Type: pkg.ConanPkg,
|
||||
Metadata: pkg.ConanLockEntry{
|
||||
Ref: "zlib/1.2.12#c67ce17f2e96b972d42393ce50a76a1a",
|
||||
Options: map[string]string{
|
||||
"fPIC": "True",
|
||||
"shared": "False",
|
||||
Options: pkg.KeyValues{
|
||||
{
|
||||
Key: "fPIC",
|
||||
Value: "True",
|
||||
},
|
||||
{
|
||||
Key: "shared",
|
||||
Value: "False",
|
||||
},
|
||||
},
|
||||
Context: "host",
|
||||
PackageID: "dfbe50feef7f3c6223a476cd5aeadb687084a646",
|
||||
@ -216,10 +222,19 @@ func TestParseConanlock(t *testing.T) {
|
||||
Type: pkg.ConanPkg,
|
||||
Metadata: pkg.ConanLockEntry{
|
||||
Ref: "bzip2/1.0.8#62a8031289639043797cf53fa876d0ef",
|
||||
Options: map[string]string{
|
||||
"build_executable": "True",
|
||||
"fPIC": "True",
|
||||
"shared": "False",
|
||||
Options: []pkg.KeyValue{
|
||||
{
|
||||
Key: "build_executable",
|
||||
Value: "True",
|
||||
},
|
||||
{
|
||||
Key: "fPIC",
|
||||
Value: "True",
|
||||
},
|
||||
{
|
||||
Key: "shared",
|
||||
Value: "False",
|
||||
},
|
||||
},
|
||||
Context: "host",
|
||||
PackageID: "c32092bf4d4bb47cf962af898e02823f499b017e",
|
||||
@ -235,9 +250,15 @@ func TestParseConanlock(t *testing.T) {
|
||||
Type: pkg.ConanPkg,
|
||||
Metadata: pkg.ConanLockEntry{
|
||||
Ref: "libbacktrace/cci.20210118#76e40b760e0bcd602d46db56b22820ab",
|
||||
Options: map[string]string{
|
||||
"fPIC": "True",
|
||||
"shared": "False",
|
||||
Options: []pkg.KeyValue{
|
||||
{
|
||||
Key: "fPIC",
|
||||
Value: "True",
|
||||
},
|
||||
{
|
||||
Key: "shared",
|
||||
Value: "False",
|
||||
},
|
||||
},
|
||||
Context: "host",
|
||||
PackageID: "dfbe50feef7f3c6223a476cd5aeadb687084a646",
|
||||
@ -253,9 +274,15 @@ func TestParseConanlock(t *testing.T) {
|
||||
Type: pkg.ConanPkg,
|
||||
Metadata: pkg.ConanLockEntry{
|
||||
Ref: "tinyxml2/9.0.0#9f13a36ebfc222cd55fe531a0a8d94d1",
|
||||
Options: map[string]string{
|
||||
"fPIC": "True",
|
||||
"shared": "False",
|
||||
Options: []pkg.KeyValue{
|
||||
{
|
||||
Key: "fPIC",
|
||||
Value: "True",
|
||||
},
|
||||
{
|
||||
Key: "shared",
|
||||
Value: "False",
|
||||
},
|
||||
},
|
||||
Context: "host",
|
||||
// intentionally remove to test missing PackageID and Prev
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debug.Module, mainModule, goVersion, architecture string, buildSettings map[string]string, cryptoSettings []string, locations ...file.Location) pkg.Package {
|
||||
func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debug.Module, mainModule, goVersion, architecture string, buildSettings pkg.KeyValues, cryptoSettings []string, locations ...file.Location) pkg.Package {
|
||||
if dep.Replace != nil {
|
||||
dep = dep.Replace
|
||||
}
|
||||
|
||||
@ -84,8 +84,8 @@ func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *exten
|
||||
return main
|
||||
}
|
||||
|
||||
version, hasVersion := gbs["vcs.revision"]
|
||||
timestamp, hasTimestamp := gbs["vcs.time"]
|
||||
version, hasVersion := gbs.Get("vcs.revision")
|
||||
timestamp, hasTimestamp := gbs.Get("vcs.time")
|
||||
|
||||
var ldflags string
|
||||
if metadata, ok := main.Metadata.(pkg.GolangBinaryBuildinfoEntry); ok {
|
||||
@ -95,7 +95,7 @@ func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *exten
|
||||
// there is a matching vcs tag to match that could be referenced. This assumption could
|
||||
// be incorrect in terms of the go.mod contents, but is not incorrect in terms of the logical
|
||||
// version of the package.
|
||||
ldflags = metadata.BuildSettings["-ldflags"]
|
||||
ldflags, _ = metadata.BuildSettings.Get("-ldflags")
|
||||
}
|
||||
|
||||
majorVersion, fullVersion := extractVersionFromLDFlags(ldflags)
|
||||
@ -207,10 +207,13 @@ func getGOARCHFromBin(r io.ReaderAt) (string, error) {
|
||||
return arch, nil
|
||||
}
|
||||
|
||||
func getBuildSettings(settings []debug.BuildSetting) map[string]string {
|
||||
m := make(map[string]string)
|
||||
func getBuildSettings(settings []debug.BuildSetting) pkg.KeyValues {
|
||||
m := make(pkg.KeyValues, 0)
|
||||
for _, s := range settings {
|
||||
m[s.Key] = s.Value
|
||||
m = append(m, pkg.KeyValue{
|
||||
Key: s.Key,
|
||||
Value: s.Value,
|
||||
})
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@ -124,10 +124,20 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
goCompiledVersion = "1.18"
|
||||
archDetails = "amd64"
|
||||
)
|
||||
defaultBuildSettings := map[string]string{
|
||||
"GOARCH": "amd64",
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
|
||||
defaultBuildSettings := []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: "amd64",
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
}
|
||||
|
||||
unmodifiedMain := pkg.Package{
|
||||
@ -275,10 +285,19 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "",
|
||||
BuildSettings: map[string]string{
|
||||
"GOAMD64": "v1",
|
||||
"GOARCH": "amd64",
|
||||
"GOOS": "darwin",
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/a/b/c",
|
||||
GoCryptoSettings: []string{"boringcrypto + fips"},
|
||||
@ -339,13 +358,31 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinaryBuildinfoEntry{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: map[string]string{
|
||||
"GOARCH": archDetails,
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
"vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4",
|
||||
"vcs.time": "2022-10-14T19:54:57Z",
|
||||
"-ldflags": `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`,
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
{
|
||||
Key: "vcs.revision",
|
||||
Value: "41bc6bb410352845f22766e27dd48ba93aa825a4",
|
||||
},
|
||||
{
|
||||
Key: "vcs.time",
|
||||
Value: "2022-10-14T19:54:57Z",
|
||||
},
|
||||
{
|
||||
Key: "-ldflags",
|
||||
Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`,
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
@ -388,13 +425,31 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinaryBuildinfoEntry{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: map[string]string{
|
||||
"GOARCH": archDetails,
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
"vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4",
|
||||
"vcs.time": "2022-10-14T19:54:57Z",
|
||||
"-ldflags": `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`,
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
{
|
||||
Key: "vcs.revision",
|
||||
Value: "41bc6bb410352845f22766e27dd48ba93aa825a4",
|
||||
},
|
||||
{
|
||||
Key: "vcs.time",
|
||||
Value: "2022-10-14T19:54:57Z",
|
||||
},
|
||||
{
|
||||
Key: "-ldflags",
|
||||
Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`,
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
@ -435,11 +490,23 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinaryBuildinfoEntry{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: map[string]string{
|
||||
"GOARCH": archDetails,
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
"-ldflags": `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`,
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
{
|
||||
Key: "-ldflags",
|
||||
Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`,
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
@ -480,11 +547,23 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinaryBuildinfoEntry{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: map[string]string{
|
||||
"GOARCH": archDetails,
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
"-ldflags": `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`,
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
{
|
||||
Key: "-ldflags",
|
||||
Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`,
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
@ -525,11 +604,23 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinaryBuildinfoEntry{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: map[string]string{
|
||||
"GOARCH": archDetails,
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
"-ldflags": `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`,
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
{
|
||||
Key: "-ldflags",
|
||||
Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`,
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
@ -571,12 +662,27 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinaryBuildinfoEntry{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: map[string]string{
|
||||
"GOARCH": archDetails,
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
"vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4",
|
||||
"vcs.time": "2022-10-14T19:54:57Z",
|
||||
BuildSettings: []pkg.KeyValue{
|
||||
{
|
||||
Key: "GOARCH",
|
||||
Value: archDetails,
|
||||
},
|
||||
{
|
||||
Key: "GOOS",
|
||||
Value: "darwin",
|
||||
},
|
||||
{
|
||||
Key: "GOAMD64",
|
||||
Value: "v1",
|
||||
},
|
||||
{
|
||||
Key: "vcs.revision",
|
||||
Value: "41bc6bb410352845f22766e27dd48ba93aa825a4",
|
||||
},
|
||||
{
|
||||
Key: "vcs.time",
|
||||
Value: "2022-10-14T19:54:57Z",
|
||||
},
|
||||
},
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
|
||||
@ -13,6 +13,17 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func keyValues(m map[string]string) []pkg.KeyValue {
|
||||
var kvs []pkg.KeyValue
|
||||
for k, v := range m {
|
||||
kvs = append(kvs, pkg.KeyValue{
|
||||
Key: k,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
return kvs
|
||||
}
|
||||
|
||||
func TestGeneratePackageCPEs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -201,7 +212,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
Type: pkg.JavaPkg,
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: keyValues(map[string]string{
|
||||
"Ant-Version": "Apache Ant 1.6.5",
|
||||
"Built-By": "tatu",
|
||||
"Created-By": "1.4.2_03-b02 (Sun Microsystems Inc.)",
|
||||
@ -212,7 +223,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
"Specification-Title": "StAX 1.0 API",
|
||||
"Specification-Vendor": "http://jcp.org/en/jsr/detail?id=173",
|
||||
"Specification-Version": "1.0",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -253,7 +264,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "/opt/jboss/keycloak/modules/system/layers/base/org/apache/cxf/impl/main/cxf-rt-bindings-xml-3.3.10.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: keyValues(map[string]string{
|
||||
"Automatic-Module-Name": "org.apache.cxf.binding.xml",
|
||||
"Bnd-LastModified": "1615836524860",
|
||||
"Build-Jdk": "1.8.0_261",
|
||||
@ -278,7 +289,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
"Specification-Vendor": "The Apache Software Foundation",
|
||||
"Specification-Version": "3.3.10",
|
||||
"Tool": "Bnd-4.2.0.201903051501",
|
||||
},
|
||||
}),
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
Path: "META-INF/maven/org.apache.cxf/cxf-rt-bindings-xml/pom.properties",
|
||||
@ -558,7 +569,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
FoundBy: "java-cataloger",
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: keyValues(map[string]string{
|
||||
"Extension-Name": "handlebars",
|
||||
"Group-Id": "org.jenkins-ci.ui",
|
||||
"Hudson-Version": "2.204",
|
||||
@ -566,7 +577,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
"Implementation-Version": "3.0.8",
|
||||
"Plugin-Version": "3.0.8",
|
||||
"Short-Name": "handlebars",
|
||||
},
|
||||
}),
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
GroupID: "org.jenkins-ci.ui",
|
||||
@ -594,10 +605,10 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
Language: pkg.Java,
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: keyValues(map[string]string{
|
||||
"Extension-Name": "active-directory",
|
||||
"Group-Id": "org.jenkins-ci.plugins",
|
||||
},
|
||||
}),
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
GroupID: "org.jenkins-ci.plugins",
|
||||
|
||||
@ -66,7 +66,7 @@ func vendorsFromJavaManifestNames(p pkg.Package) fieldCandidateSet {
|
||||
|
||||
for _, name := range javaManifestNameFields {
|
||||
if metadata.Manifest.Main != nil {
|
||||
if value, exists := metadata.Manifest.Main[name]; exists {
|
||||
if value, exists := metadata.Manifest.Main.Get(name); exists {
|
||||
if !startsWithTopLevelDomain(value) {
|
||||
vendors.add(fieldCandidate{
|
||||
value: normalizePersonName(value),
|
||||
@ -75,12 +75,12 @@ func vendorsFromJavaManifestNames(p pkg.Package) fieldCandidateSet {
|
||||
}
|
||||
}
|
||||
}
|
||||
if metadata.Manifest.NamedSections != nil {
|
||||
for _, section := range metadata.Manifest.NamedSections {
|
||||
if metadata.Manifest.Sections != nil {
|
||||
for _, section := range metadata.Manifest.Sections {
|
||||
if section == nil {
|
||||
continue
|
||||
}
|
||||
if value, exists := section[name]; exists {
|
||||
if value, exists := section.Get(name); exists {
|
||||
if !startsWithTopLevelDomain(value) {
|
||||
vendors.add(fieldCandidate{
|
||||
value: normalizePersonName(value),
|
||||
@ -275,13 +275,13 @@ func GetManifestFieldGroupIDs(manifest *pkg.JavaManifest, fields []string) (grou
|
||||
}
|
||||
|
||||
for _, name := range fields {
|
||||
if value, exists := manifest.Main[name]; exists {
|
||||
if value, exists := manifest.Main.Get(name); exists {
|
||||
if startsWithTopLevelDomain(value) {
|
||||
groupIDs = append(groupIDs, cleanGroupID(value))
|
||||
}
|
||||
}
|
||||
for _, section := range manifest.NamedSections {
|
||||
if value, exists := section[name]; exists {
|
||||
for _, section := range manifest.Sections {
|
||||
if value, exists := section.Get(name); exists {
|
||||
if startsWithTopLevelDomain(value) {
|
||||
groupIDs = append(groupIDs, cleanGroupID(value))
|
||||
}
|
||||
|
||||
@ -188,8 +188,11 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Extension-Name": "io.jenkins-ci.plugin.thing",
|
||||
Main: pkg.KeyValues{
|
||||
{
|
||||
Key: "Extension-Name",
|
||||
Value: "io.jenkins-ci.plugin.thing",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -201,9 +204,16 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
NamedSections: map[string]map[string]string{
|
||||
"section": {
|
||||
"Extension-Name": "io.jenkins-ci.plugin.thing",
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "section",
|
||||
},
|
||||
{
|
||||
Key: "Extension-Name",
|
||||
Value: "io.jenkins-ci.plugin.thing",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -216,20 +226,20 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: []pkg.KeyValue{
|
||||
// positive cases
|
||||
// tier 1
|
||||
"Extension-Name": "io.jenkins-ci.plugin.1",
|
||||
"Specification-Vendor": "io.jenkins-ci.plugin.2",
|
||||
"Implementation-Vendor": "io.jenkins-ci.plugin.3",
|
||||
"Bundle-SymbolicName": "io.jenkins-ci.plugin.4",
|
||||
"Implementation-Vendor-Id": "io.jenkins-ci.plugin.5",
|
||||
"Implementation-Title": "io.jenkins-ci.plugin.6",
|
||||
"Bundle-Activator": "io.jenkins-ci.plugin.7",
|
||||
{Key: "Extension-Name", Value: "io.jenkins-ci.plugin.1"},
|
||||
{Key: "Specification-Vendor", Value: "io.jenkins-ci.plugin.2"},
|
||||
{Key: "Implementation-Vendor", Value: "io.jenkins-ci.plugin.3"},
|
||||
{Key: "Bundle-SymbolicName", Value: "io.jenkins-ci.plugin.4"},
|
||||
{Key: "Implementation-Vendor-Id", Value: "io.jenkins-ci.plugin.5"},
|
||||
{Key: "Implementation-Title", Value: "io.jenkins-ci.plugin.6"},
|
||||
{Key: "Bundle-Activator", Value: "io.jenkins-ci.plugin.7"},
|
||||
// tier 2
|
||||
"Automatic-Module-Name": "io.jenkins-ci.plugin.8",
|
||||
"Main-Class": "io.jenkins-ci.plugin.9",
|
||||
"Package": "io.jenkins-ci.plugin.10",
|
||||
{Key: "Automatic-Module-Name", Value: "io.jenkins-ci.plugin.8"},
|
||||
{Key: "Main-Class", Value: "io.jenkins-ci.plugin.9"},
|
||||
{Key: "Package", Value: "io.jenkins-ci.plugin.10"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -249,11 +259,11 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: []pkg.KeyValue{
|
||||
// positive cases
|
||||
"Automatic-Module-Name": "io.jenkins-ci.plugin.8",
|
||||
"Main-Class": "io.jenkins-ci.plugin.9",
|
||||
"Package": "io.jenkins-ci.plugin.10",
|
||||
{Key: "Automatic-Module-Name", Value: "io.jenkins-ci.plugin.8"},
|
||||
{Key: "Main-Class", Value: "io.jenkins-ci.plugin.9"},
|
||||
{Key: "Package", Value: "io.jenkins-ci.plugin.10"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -269,10 +279,10 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
Main: []pkg.KeyValue{
|
||||
// negative cases
|
||||
"Extension-Name": "not.a-group.id",
|
||||
"bogus": "io.jenkins-ci.plugin.please-dont-find-me",
|
||||
{Key: "Extension-Name", Value: "not.a-group.id"},
|
||||
{Key: "bogus", Value: "io.jenkins-ci.plugin.please-dont-find-me"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -284,21 +294,55 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
NamedSections: map[string]map[string]string{
|
||||
"section": {
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "section",
|
||||
},
|
||||
// positive cases
|
||||
// tier 1
|
||||
"Extension-Name": "io.jenkins-ci.plugin.1",
|
||||
"Specification-Vendor": "io.jenkins-ci.plugin.2",
|
||||
"Implementation-Vendor": "io.jenkins-ci.plugin.3",
|
||||
"Bundle-SymbolicName": "io.jenkins-ci.plugin.4",
|
||||
"Implementation-Vendor-Id": "io.jenkins-ci.plugin.5",
|
||||
"Implementation-Title": "io.jenkins-ci.plugin.6",
|
||||
"Bundle-Activator": "io.jenkins-ci.plugin.7",
|
||||
{
|
||||
Key: "Extension-Name",
|
||||
Value: "io.jenkins-ci.plugin.1",
|
||||
},
|
||||
{
|
||||
Key: "Specification-Vendor",
|
||||
Value: "io.jenkins-ci.plugin.2",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "io.jenkins-ci.plugin.3",
|
||||
},
|
||||
{
|
||||
Key: "Bundle-SymbolicName",
|
||||
Value: "io.jenkins-ci.plugin.4",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Vendor-Id",
|
||||
Value: "io.jenkins-ci.plugin.5",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Title",
|
||||
Value: "io.jenkins-ci.plugin.6",
|
||||
},
|
||||
{
|
||||
Key: "Bundle-Activator",
|
||||
Value: "io.jenkins-ci.plugin.7",
|
||||
},
|
||||
// tier 2
|
||||
"Automatic-Module-Name": "io.jenkins-ci.plugin.8",
|
||||
"Main-Class": "io.jenkins-ci.plugin.9",
|
||||
"Package": "io.jenkins-ci.plugin.10",
|
||||
{
|
||||
Key: "Automatic-Module-Name",
|
||||
Value: "io.jenkins-ci.plugin.8",
|
||||
},
|
||||
{
|
||||
Key: "Main-Class",
|
||||
Value: "io.jenkins-ci.plugin.9",
|
||||
},
|
||||
{
|
||||
Key: "Package",
|
||||
Value: "io.jenkins-ci.plugin.10",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -319,11 +363,20 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
NamedSections: map[string]map[string]string{
|
||||
"section": {
|
||||
// negative cases
|
||||
"Extension-Name": "not.a-group.id",
|
||||
"bogus": "io.jenkins-ci.plugin.please-dont-find-me",
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "section",
|
||||
},
|
||||
{
|
||||
Key: "Extension-Name",
|
||||
Value: "not.a-group.id",
|
||||
},
|
||||
{
|
||||
Key: "bogus",
|
||||
Value: "io.jenkins-ci.plugin.please-dont-find-me",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -403,11 +456,21 @@ func Test_vendorsFromJavaManifestNames(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
NamedSections: map[string]map[string]string{
|
||||
"section": {
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "section",
|
||||
},
|
||||
// positive cases
|
||||
"Specification-Vendor": "Alex Goodman",
|
||||
"Implementation-Vendor": "William Goodman",
|
||||
{
|
||||
Key: "Specification-Vendor",
|
||||
Value: "Alex Goodman",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "William Goodman",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -420,11 +483,22 @@ func Test_vendorsFromJavaManifestNames(t *testing.T) {
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
NamedSections: map[string]map[string]string{
|
||||
"section": {
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "section",
|
||||
},
|
||||
// negative cases
|
||||
"Specification-Vendor": "io.jenkins-ci.plugin.thing",
|
||||
"Implementation-Vendor-ID": "William Goodman",
|
||||
|
||||
{
|
||||
Key: "Specification-Vendor",
|
||||
Value: "io.jenkins-ci.plugin.thing",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Vendor-ID",
|
||||
Value: "William Goodman",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -459,8 +533,11 @@ func Test_groupIDsFromJavaManifest(t *testing.T) {
|
||||
{
|
||||
name: "spring-foo",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Implementation-Vendor": "org.foo",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "org.foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"org.foo"},
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/gookit/color"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
@ -197,31 +198,31 @@ func TestParseJar(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-jenkins-plugin.hpi",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Specification-Title": "Example Jenkins Plugin",
|
||||
"Specification-Version": "1.0",
|
||||
"Implementation-Title": "Example Jenkins Plugin",
|
||||
"Implementation-Version": "1.0-SNAPSHOT",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
{Key: "Created-By", Value: "Maven Archiver 3.6.0"},
|
||||
{Key: "Build-Jdk-Spec", Value: "18"},
|
||||
{Key: "Specification-Title", Value: "Example Jenkins Plugin"},
|
||||
{Key: "Specification-Version", Value: "1.0"},
|
||||
{Key: "Implementation-Title", Value: "Example Jenkins Plugin"},
|
||||
{Key: "Implementation-Version", Value: "1.0-SNAPSHOT"},
|
||||
{Key: "Group-Id", Value: "io.jenkins.plugins"},
|
||||
{Key: "Short-Name", Value: "example-jenkins-plugin"},
|
||||
{Key: "Long-Name", Value: "Example Jenkins Plugin"},
|
||||
{Key: "Hudson-Version", Value: "2.204"},
|
||||
{Key: "Jenkins-Version", Value: "2.204"},
|
||||
{Key: "Plugin-Dependencies", Value: "structs:1.20"},
|
||||
{Key: "Plugin-Developers", Value: ""},
|
||||
{Key: "Plugin-License-Name", Value: "MIT License"},
|
||||
{Key: "Plugin-License-Url", Value: "https://opensource.org/licenses/MIT"},
|
||||
{Key: "Plugin-ScmUrl", Value: "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin"},
|
||||
// extra fields...
|
||||
//"Archiver-Version": "Plexus Archiver",
|
||||
"Plugin-License-Url": "https://opensource.org/licenses/MIT",
|
||||
"Plugin-License-Name": "MIT License",
|
||||
"Created-By": "Maven Archiver 3.6.0",
|
||||
//"Built-By": "?",
|
||||
//"Build-Jdk": "14.0.1",
|
||||
"Build-Jdk-Spec": "18",
|
||||
"Jenkins-Version": "2.204",
|
||||
//"Minimum-Java-Version": "1.8",
|
||||
"Plugin-Developers": "",
|
||||
"Plugin-ScmUrl": "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin",
|
||||
//"Extension-Name": "example-jenkins-plugin",
|
||||
"Short-Name": "example-jenkins-plugin",
|
||||
"Group-Id": "io.jenkins.plugins",
|
||||
"Plugin-Dependencies": "structs:1.20",
|
||||
//"Plugin-Version": "1.0-SNAPSHOT (private-07/09/2020 13:30-?)",
|
||||
"Hudson-Version": "2.204",
|
||||
"Long-Name": "Example Jenkins Plugin",
|
||||
//{Key: "Minimum-Java-Version", Value: "1.8"},
|
||||
//{Key: "Archiver-Version", Value: "Plexus Archiver"},
|
||||
//{Key: "Built-By", Value: "?"},
|
||||
//{Key: "Build-Jdk", Value: "14.0.1"},
|
||||
//{Key: "Extension-Name", Value: "example-jenkins-plugin"},
|
||||
//{Key: "Plugin-Version", Value: "1.0-SNAPSHOT (private-07/09/2020 13:30-?)"},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -255,9 +256,15 @@ func TestParseJar(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Main-Class": "hello.HelloWorld",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Key: "Main-Class",
|
||||
Value: "hello.HelloWorld",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -326,14 +333,32 @@ func TestParseJar(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
// extra fields...
|
||||
"Archiver-Version": "Plexus Archiver",
|
||||
"Created-By": "Apache Maven 3.8.6",
|
||||
//"Built-By": "?",
|
||||
//"Build-Jdk": "14.0.1",
|
||||
"Main-Class": "hello.HelloWorld",
|
||||
{
|
||||
Key: "Archiver-Version",
|
||||
Value: "Plexus Archiver",
|
||||
},
|
||||
{
|
||||
Key: "Created-By",
|
||||
Value: "Apache Maven 3.8.6",
|
||||
},
|
||||
//{
|
||||
// Key: "Built-By",
|
||||
// Value: "?",
|
||||
//},
|
||||
//{
|
||||
// Key: "Build-Jdk",
|
||||
// Value: "14.0.1",
|
||||
//},
|
||||
{
|
||||
Key: "Main-Class",
|
||||
Value: "hello.HelloWorld",
|
||||
},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -455,7 +480,14 @@ func TestParseJar(t *testing.T) {
|
||||
// ignore select fields (only works for the main section)
|
||||
for _, field := range test.ignoreExtras {
|
||||
if metadata.Manifest != nil && metadata.Manifest.Main != nil {
|
||||
delete(metadata.Manifest.Main, field)
|
||||
newMain := make(pkg.KeyValues, 0)
|
||||
for i, kv := range metadata.Manifest.Main {
|
||||
if kv.Key == field {
|
||||
continue
|
||||
}
|
||||
newMain = append(newMain, metadata.Manifest.Main[i])
|
||||
}
|
||||
metadata.Manifest.Main = newMain
|
||||
}
|
||||
}
|
||||
|
||||
@ -1158,32 +1190,32 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/jar-metadata/cache/jackson-core-2.15.2.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Build-Jdk-Spec": "1.8",
|
||||
"Bundle-Description": "Core Jackson processing abstractions",
|
||||
"Bundle-DocURL": "https://github.com/FasterXML/jackson-core",
|
||||
"Bundle-License": "https://www.apache.org/licenses/LICENSE-2.0.txt",
|
||||
"Bundle-ManifestVersion": "2",
|
||||
"Bundle-Name": "Jackson-core",
|
||||
"Bundle-SymbolicName": "com.fasterxml.jackson.core.jackson-core",
|
||||
"Bundle-Vendor": "FasterXML",
|
||||
"Bundle-Version": "2.15.2",
|
||||
"Created-By": "Apache Maven Bundle Plugin 5.1.8",
|
||||
"Export-Package": "com.fasterxml.jackson.core;version...snip",
|
||||
"Implementation-Title": "Jackson-core",
|
||||
"Implementation-Vendor": "FasterXML",
|
||||
"Implementation-Vendor-Id": "com.fasterxml.jackson.core",
|
||||
"Implementation-Version": "2.15.2",
|
||||
"Import-Package": "com.fasterxml.jackson.core;version=...snip",
|
||||
"Manifest-Version": "1.0",
|
||||
"Multi-Release": "true",
|
||||
"Require-Capability": `osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"`,
|
||||
"Specification-Title": "Jackson-core",
|
||||
"Specification-Vendor": "FasterXML",
|
||||
"Specification-Version": "2.15.2",
|
||||
"Tool": "Bnd-6.3.1.202206071316",
|
||||
"X-Compile-Source-JDK": "1.8",
|
||||
"X-Compile-Target-JDK": "1.8",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
{Key: "Bundle-License", Value: "https://www.apache.org/licenses/LICENSE-2.0.txt"},
|
||||
{Key: "Bundle-SymbolicName", Value: "com.fasterxml.jackson.core.jackson-core"},
|
||||
{Key: "Implementation-Vendor-Id", Value: "com.fasterxml.jackson.core"},
|
||||
{Key: "Specification-Title", Value: "Jackson-core"},
|
||||
{Key: "Bundle-DocURL", Value: "https://github.com/FasterXML/jackson-core"},
|
||||
{Key: "Import-Package", Value: "com.fasterxml.jackson.core;version=...snip"},
|
||||
{Key: "Require-Capability", Value: `osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"`},
|
||||
{Key: "Export-Package", Value: "com.fasterxml.jackson.core;version...snip"},
|
||||
{Key: "Bundle-Name", Value: "Jackson-core"},
|
||||
{Key: "Multi-Release", Value: "true"},
|
||||
{Key: "Build-Jdk-Spec", Value: "1.8"},
|
||||
{Key: "Bundle-Description", Value: "Core Jackson processing abstractions"},
|
||||
{Key: "Implementation-Title", Value: "Jackson-core"},
|
||||
{Key: "Implementation-Version", Value: "2.15.2"},
|
||||
{Key: "Bundle-ManifestVersion", Value: "2"},
|
||||
{Key: "Specification-Vendor", Value: "FasterXML"},
|
||||
{Key: "Bundle-Vendor", Value: "FasterXML"},
|
||||
{Key: "Tool", Value: "Bnd-6.3.1.202206071316"},
|
||||
{Key: "Implementation-Vendor", Value: "FasterXML"},
|
||||
{Key: "Bundle-Version", Value: "2.15.2"},
|
||||
{Key: "X-Compile-Target-JDK", Value: "1.8"},
|
||||
{Key: "X-Compile-Source-JDK", Value: "1.8"},
|
||||
{Key: "Created-By", Value: "Apache Maven Bundle Plugin 5.1.8"},
|
||||
{Key: "Specification-Version", Value: "2.15.2"},
|
||||
},
|
||||
},
|
||||
// not under test
|
||||
@ -1212,32 +1244,32 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/jar-metadata/cache/com.fasterxml.jackson.core.jackson-core-2.15.2.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Build-Jdk-Spec": "1.8",
|
||||
"Bundle-Description": "Core Jackson processing abstractions",
|
||||
"Bundle-DocURL": "https://github.com/FasterXML/jackson-core",
|
||||
"Bundle-License": "https://www.apache.org/licenses/LICENSE-2.0.txt",
|
||||
"Bundle-ManifestVersion": "2",
|
||||
"Bundle-Name": "Jackson-core",
|
||||
"Bundle-SymbolicName": "com.fasterxml.jackson.core.jackson-core",
|
||||
"Bundle-Vendor": "FasterXML",
|
||||
"Bundle-Version": "2.15.2",
|
||||
"Created-By": "Apache Maven Bundle Plugin 5.1.8",
|
||||
"Export-Package": "com.fasterxml.jackson.core;version...snip",
|
||||
"Implementation-Title": "Jackson-core",
|
||||
"Implementation-Vendor": "FasterXML",
|
||||
"Implementation-Vendor-Id": "com.fasterxml.jackson.core",
|
||||
"Implementation-Version": "2.15.2",
|
||||
"Import-Package": "com.fasterxml.jackson.core;version=...snip",
|
||||
"Manifest-Version": "1.0",
|
||||
"Multi-Release": "true",
|
||||
"Require-Capability": `osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"`,
|
||||
"Specification-Title": "Jackson-core",
|
||||
"Specification-Vendor": "FasterXML",
|
||||
"Specification-Version": "2.15.2",
|
||||
"Tool": "Bnd-6.3.1.202206071316",
|
||||
"X-Compile-Source-JDK": "1.8",
|
||||
"X-Compile-Target-JDK": "1.8",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
{Key: "Bundle-License", Value: "https://www.apache.org/licenses/LICENSE-2.0.txt"},
|
||||
{Key: "Bundle-SymbolicName", Value: "com.fasterxml.jackson.core.jackson-core"},
|
||||
{Key: "Implementation-Vendor-Id", Value: "com.fasterxml.jackson.core"},
|
||||
{Key: "Specification-Title", Value: "Jackson-core"},
|
||||
{Key: "Bundle-DocURL", Value: "https://github.com/FasterXML/jackson-core"},
|
||||
{Key: "Import-Package", Value: "com.fasterxml.jackson.core;version=...snip"},
|
||||
{Key: "Require-Capability", Value: `osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"`},
|
||||
{Key: "Export-Package", Value: "com.fasterxml.jackson.core;version...snip"},
|
||||
{Key: "Bundle-Name", Value: "Jackson-core"},
|
||||
{Key: "Multi-Release", Value: "true"},
|
||||
{Key: "Build-Jdk-Spec", Value: "1.8"},
|
||||
{Key: "Bundle-Description", Value: "Core Jackson processing abstractions"},
|
||||
{Key: "Implementation-Title", Value: "Jackson-core"},
|
||||
{Key: "Implementation-Version", Value: "2.15.2"},
|
||||
{Key: "Bundle-ManifestVersion", Value: "2"},
|
||||
{Key: "Specification-Vendor", Value: "FasterXML"},
|
||||
{Key: "Bundle-Vendor", Value: "FasterXML"},
|
||||
{Key: "Tool", Value: "Bnd-6.3.1.202206071316"},
|
||||
{Key: "Implementation-Vendor", Value: "FasterXML"},
|
||||
{Key: "Bundle-Version", Value: "2.15.2"},
|
||||
{Key: "X-Compile-Target-JDK", Value: "1.8"},
|
||||
{Key: "X-Compile-Source-JDK", Value: "1.8"},
|
||||
{Key: "Created-By", Value: "Apache Maven Bundle Plugin 5.1.8"},
|
||||
{Key: "Specification-Version", Value: "2.15.2"},
|
||||
},
|
||||
},
|
||||
// not under test
|
||||
@ -1261,11 +1293,23 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/jar-metadata/cache/api-all-2.0.0-sources.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Build-Jdk": "1.8.0_191",
|
||||
"Built-By": "elecharny",
|
||||
"Created-By": "Apache Maven 3.6.0",
|
||||
"Manifest-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Key: "Built-By",
|
||||
Value: "elecharny",
|
||||
},
|
||||
{
|
||||
Key: "Created-By",
|
||||
Value: "Apache Maven 3.6.0",
|
||||
},
|
||||
{
|
||||
Key: "Build-Jdk",
|
||||
Value: "1.8.0_191",
|
||||
},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -1314,10 +1358,25 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
if tt.assignParent {
|
||||
assignParent(&tt.expectedPkgs[0], tt.expectedPkgs[1:]...)
|
||||
}
|
||||
for i := range tt.expectedPkgs {
|
||||
tt.expectedPkgs[i].SetID()
|
||||
}
|
||||
pkgtest.NewCatalogTester().
|
||||
FromFile(t, generateJavaMetadataJarFixture(t, tt.fixtureName)).
|
||||
Expects(tt.expectedPkgs, tt.expectedRelationships).
|
||||
WithCompareOptions(cmpopts.IgnoreFields(pkg.JavaArchive{}, "ArchiveDigests")).
|
||||
WithCompareOptions(
|
||||
cmpopts.IgnoreFields(pkg.JavaArchive{}, "ArchiveDigests"),
|
||||
cmp.Comparer(func(x, y pkg.KeyValue) bool {
|
||||
if x.Key != y.Key {
|
||||
return false
|
||||
}
|
||||
if x.Value != y.Value {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}),
|
||||
).
|
||||
TestParser(t, gap.parseJavaArchive)
|
||||
})
|
||||
}
|
||||
|
||||
@ -24,8 +24,11 @@ func Test_packageURL(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -49,8 +52,11 @@ func Test_packageURL(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -74,8 +80,11 @@ func Test_packageURL(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -101,8 +110,11 @@ func Test_packageURL(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
@ -163,8 +175,11 @@ func Test_groupIDFromJavaMetadata(t *testing.T) {
|
||||
name: "java manifest",
|
||||
metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Implementation-Vendor": "org.anchore",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "org.anchore",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
@ -20,7 +19,7 @@ const manifestGlob = "/META-INF/MANIFEST.MF"
|
||||
//nolint:funlen
|
||||
func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error) {
|
||||
var manifest pkg.JavaManifest
|
||||
var sections []map[string]string
|
||||
sections := make([]pkg.KeyValues, 0)
|
||||
|
||||
currentSection := func() int {
|
||||
return len(sections) - 1
|
||||
@ -51,7 +50,9 @@ func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error)
|
||||
continue
|
||||
}
|
||||
|
||||
sections[currentSection()][lastKey] += strings.TrimSpace(line)
|
||||
lastSection := sections[currentSection()]
|
||||
|
||||
sections[currentSection()][len(lastSection)-1].Value += strings.TrimSpace(line)
|
||||
|
||||
continue
|
||||
}
|
||||
@ -73,10 +74,13 @@ func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error)
|
||||
|
||||
if lastKey == "" {
|
||||
// we're entering a new section
|
||||
sections = append(sections, make(map[string]string))
|
||||
sections = append(sections, make(pkg.KeyValues, 0))
|
||||
}
|
||||
|
||||
sections[currentSection()][key] = value
|
||||
sections[currentSection()] = append(sections[currentSection()], pkg.KeyValue{
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
|
||||
// keep track of key for potential future continuations
|
||||
lastKey = key
|
||||
@ -89,20 +93,7 @@ func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error)
|
||||
if len(sections) > 0 {
|
||||
manifest.Main = sections[0]
|
||||
if len(sections) > 1 {
|
||||
manifest.NamedSections = make(map[string]map[string]string)
|
||||
for i, s := range sections[1:] {
|
||||
name, ok := s["Name"]
|
||||
if !ok {
|
||||
// per the manifest spec (https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#jar-manifest)
|
||||
// this should never happen. If it does, we want to know about it, but not necessarily stop
|
||||
// cataloging entirely... for this reason we only log.
|
||||
log.Debugf("java manifest section found without a name: %s", path)
|
||||
name = strconv.Itoa(i)
|
||||
} else {
|
||||
delete(s, "Name")
|
||||
}
|
||||
manifest.NamedSections[name] = s
|
||||
}
|
||||
manifest.Sections = sections[1:]
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,12 +118,12 @@ func extractNameFromApacheMavenBundlePlugin(manifest *pkg.JavaManifest) string {
|
||||
// The computed symbolic name is also stored in the $(maven-symbolicname) property in case you want to add attributes or directives to it.
|
||||
//
|
||||
if manifest != nil {
|
||||
if strings.Contains(manifest.Main["Created-By"], "Apache Maven Bundle Plugin") {
|
||||
if symbolicName := manifest.Main["Bundle-SymbolicName"]; symbolicName != "" {
|
||||
if strings.Contains(manifest.Main.MustGet("Created-By"), "Apache Maven Bundle Plugin") {
|
||||
if symbolicName := manifest.Main.MustGet("Bundle-SymbolicName"); symbolicName != "" {
|
||||
// It is possible that `Bundle-SymbolicName` is just the groupID (like in the case of
|
||||
// https://repo1.maven.org/maven2/com/google/oauth-client/google-oauth-client/1.25.0/google-oauth-client-1.25.0.jar),
|
||||
// so if `Implementation-Vendor-Id` is equal to `Bundle-SymbolicName`, bail on this logic
|
||||
if vendorID := manifest.Main["Implementation-Vendor-Id"]; vendorID != "" && vendorID == symbolicName {
|
||||
if vendorID := manifest.Main.MustGet("Implementation-Vendor-Id"); vendorID != "" && vendorID == symbolicName {
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -212,21 +203,21 @@ func selectName(manifest *pkg.JavaManifest, filenameObj archiveFilename) string
|
||||
// remaining fields in the manifest is a bit of a free-for-all depending on the build tooling used and package maintainer preferences
|
||||
if manifest != nil {
|
||||
switch {
|
||||
case manifest.Main["Name"] != "":
|
||||
case manifest.Main.MustGet("Name") != "":
|
||||
// Manifest original spec...
|
||||
return manifest.Main["Name"]
|
||||
case manifest.Main["Bundle-Name"] != "":
|
||||
return manifest.Main.MustGet("Name")
|
||||
case manifest.Main.MustGet("Bundle-Name") != "":
|
||||
// BND tooling... TODO: this does not seem accurate (I don't see a reference in the BND tooling docs for this)
|
||||
return manifest.Main["Bundle-Name"]
|
||||
case manifest.Main["Short-Name"] != "":
|
||||
return manifest.Main.MustGet("Bundle-Name")
|
||||
case manifest.Main.MustGet("Short-Name") != "":
|
||||
// Jenkins...
|
||||
return manifest.Main["Short-Name"]
|
||||
case manifest.Main["Extension-Name"] != "":
|
||||
return manifest.Main.MustGet("Short-Name")
|
||||
case manifest.Main.MustGet("Extension-Name") != "":
|
||||
// Jenkins...
|
||||
return manifest.Main["Extension-Name"]
|
||||
case manifest.Main["Implementation-Title"] != "":
|
||||
return manifest.Main.MustGet("Extension-Name")
|
||||
case manifest.Main.MustGet("Implementation-Title") != "":
|
||||
// last ditch effort...
|
||||
return manifest.Main["Implementation-Title"]
|
||||
return manifest.Main.MustGet("Implementation-Title")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
@ -278,12 +269,12 @@ func selectLicenses(manifest *pkg.JavaManifest) []string {
|
||||
}
|
||||
|
||||
func fieldValueFromManifest(manifest pkg.JavaManifest, fieldName string) string {
|
||||
if value := manifest.Main[fieldName]; value != "" {
|
||||
if value := manifest.Main.MustGet(fieldName); value != "" {
|
||||
return value
|
||||
}
|
||||
|
||||
for _, section := range manifest.NamedSections {
|
||||
if value := section[fieldName]; value != "" {
|
||||
for _, section := range manifest.Sections {
|
||||
if value := section.MustGet(fieldName); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,41 +19,63 @@ func TestParseJavaManifest(t *testing.T) {
|
||||
{
|
||||
fixture: "test-fixtures/manifest/small",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/manifest/standard-info",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Name": "the-best-name",
|
||||
"Manifest-Version": "1.0",
|
||||
"Specification-Title": "the-spec-title",
|
||||
"Specification-Version": "the-spec-version",
|
||||
"Specification-Vendor": "the-spec-vendor",
|
||||
"Implementation-Title": "the-impl-title",
|
||||
"Implementation-Version": "the-impl-version",
|
||||
"Implementation-Vendor": "the-impl-vendor",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
{Key: "Name", Value: "the-best-name"},
|
||||
{Key: "Specification-Title", Value: "the-spec-title"},
|
||||
{Key: "Specification-Vendor", Value: "the-spec-vendor"},
|
||||
{Key: "Specification-Version", Value: "the-spec-version"},
|
||||
{Key: "Implementation-Title", Value: "the-impl-title"},
|
||||
{Key: "Implementation-Vendor", Value: "the-impl-vendor"},
|
||||
{Key: "Implementation-Version", Value: "the-impl-version"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/manifest/extra-info",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Archiver-Version": "Plexus Archiver",
|
||||
"Created-By": "Apache Maven 3.6.3",
|
||||
},
|
||||
NamedSections: map[string]map[string]string{
|
||||
"thing-1": {
|
||||
"Built-By": "?",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
"1": {
|
||||
"Build-Jdk": "14.0.1",
|
||||
"Main-Class": "hello.HelloWorld",
|
||||
{
|
||||
Key: "Archiver-Version",
|
||||
Value: "Plexus Archiver",
|
||||
},
|
||||
{
|
||||
Key: "Created-By",
|
||||
Value: "Apache Maven 3.6.3",
|
||||
},
|
||||
},
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "thing-1",
|
||||
},
|
||||
{
|
||||
Key: "Built-By",
|
||||
Value: "?",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
Key: "Build-Jdk",
|
||||
Value: "14.0.1",
|
||||
},
|
||||
{
|
||||
Key: "Main-Class",
|
||||
Value: "hello.HelloWorld",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -61,23 +83,34 @@ func TestParseJavaManifest(t *testing.T) {
|
||||
{
|
||||
fixture: "test-fixtures/manifest/extra-empty-lines",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Archiver-Version": "Plexus Archiver",
|
||||
"Created-By": "Apache Maven 3.6.3",
|
||||
Main: pkg.KeyValues{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Key: "Archiver-Version",
|
||||
Value: "Plexus Archiver",
|
||||
},
|
||||
{
|
||||
Key: "Created-By",
|
||||
Value: "Apache Maven 3.6.3",
|
||||
},
|
||||
},
|
||||
NamedSections: map[string]map[string]string{
|
||||
"thing-1": {
|
||||
"Built-By": "?",
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{Key: "Name", Value: "thing-1"},
|
||||
{Key: "Built-By", Value: "?"},
|
||||
},
|
||||
"thing-2": {
|
||||
"Built-By": "someone!",
|
||||
{
|
||||
{Key: "Name", Value: "thing-2"},
|
||||
{Key: "Built-By", Value: "someone!"},
|
||||
},
|
||||
"2": {
|
||||
"Other": "things",
|
||||
{
|
||||
{Key: "Other", Value: "things"},
|
||||
},
|
||||
"3": {
|
||||
"Last": "item",
|
||||
{
|
||||
{Key: "Last", Value: "item"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -85,9 +118,15 @@ func TestParseJavaManifest(t *testing.T) {
|
||||
{
|
||||
fixture: "test-fixtures/manifest/continuation",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Plugin-ScmUrl": "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin",
|
||||
Main: pkg.KeyValues{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Key: "Plugin-ScmUrl",
|
||||
Value: "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -95,9 +134,15 @@ func TestParseJavaManifest(t *testing.T) {
|
||||
// regression test, we should always keep the full version
|
||||
fixture: "test-fixtures/manifest/version-with-date",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Implementation-Version": "1.3 2244 October 5 2005",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Version",
|
||||
Value: "1.3 2244 October 5 2005",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -106,9 +151,15 @@ func TestParseJavaManifest(t *testing.T) {
|
||||
// https://github.com/anchore/syft/issues/2179
|
||||
fixture: "test-fixtures/manifest/leading-space",
|
||||
expected: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Key-keykeykey": "initialconfig:com$ # aka not empty line",
|
||||
"should": "parse",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Key-keykeykey",
|
||||
Value: "initialconfig:com$ # aka not empty line",
|
||||
},
|
||||
{
|
||||
Key: "should",
|
||||
Value: "parse",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -154,8 +205,11 @@ func TestSelectName(t *testing.T) {
|
||||
desc: "Get name from Implementation-Title",
|
||||
archive: archiveFilename{},
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Implementation-Title": "maven-wrapper",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Implementation-Title",
|
||||
Value: "maven-wrapper",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "maven-wrapper",
|
||||
@ -163,9 +217,15 @@ func TestSelectName(t *testing.T) {
|
||||
{
|
||||
desc: "Implementation-Title does not override name from filename",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Name": "foo",
|
||||
"Implementation-Title": "maven-wrapper",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "foo",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Title",
|
||||
Value: "maven-wrapper",
|
||||
},
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/omg.jar"),
|
||||
@ -174,11 +234,11 @@ func TestSelectName(t *testing.T) {
|
||||
{
|
||||
desc: "Use the artifact ID baked by the Apache Maven Bundle Plugin",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Created-By": "Apache Maven Bundle Plugin",
|
||||
"Bundle-SymbolicName": "com.atlassian.gadgets.atlassian-gadgets-api",
|
||||
"Name": "foo",
|
||||
"Implementation-Title": "maven-wrapper",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Created-By", Value: "Apache Maven Bundle Plugin"},
|
||||
{Key: "Bundle-SymbolicName", Value: "com.atlassian.gadgets.atlassian-gadgets-api"},
|
||||
{Key: "Name", Value: "foo"},
|
||||
{Key: "Implementation-Title", Value: "maven-wrapper"},
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/omg.jar"),
|
||||
@ -188,11 +248,11 @@ func TestSelectName(t *testing.T) {
|
||||
// example: pkg:maven/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-beans@5.3.26_1
|
||||
desc: "Apache Maven Bundle Plugin might bake a version in the created-by field",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Created-By": "Apache Maven Bundle Plugin 5.1.6",
|
||||
"Bundle-SymbolicName": "com.atlassian.gadgets.atlassian-gadgets-api",
|
||||
"Name": "foo",
|
||||
"Implementation-Title": "maven-wrapper",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Created-By", Value: "Apache Maven Bundle Plugin 5.1.6"},
|
||||
{Key: "Bundle-SymbolicName", Value: "com.atlassian.gadgets.atlassian-gadgets-api"},
|
||||
{Key: "Name", Value: "foo"},
|
||||
{Key: "Implementation-Title", Value: "maven-wrapper"},
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/omg.jar"),
|
||||
@ -201,9 +261,15 @@ func TestSelectName(t *testing.T) {
|
||||
{
|
||||
desc: "Filename looks like a groupid + artifact id",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Name": "foo",
|
||||
"Implementation-Title": "maven-wrapper",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "foo",
|
||||
},
|
||||
{
|
||||
Key: "Implementation-Title",
|
||||
Value: "maven-wrapper",
|
||||
},
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/com.atlassian.gadgets.atlassian-gadgets-api.jar"),
|
||||
@ -228,8 +294,11 @@ func TestSelectName(t *testing.T) {
|
||||
{
|
||||
desc: "Skip stripping groupId prefix from archive filename for org.eclipse",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Automatic-Module-Name": "org.eclipse.ant.core",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Automatic-Module-Name",
|
||||
Value: "org.eclipse.ant.core",
|
||||
},
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/org.eclipse.ant.core-3.7.0.jar"),
|
||||
@ -239,21 +308,21 @@ func TestSelectName(t *testing.T) {
|
||||
// example: pkg:maven/com.google.oauth-client/google-oauth-client@1.25.0
|
||||
desc: "skip Apache Maven Bundle Plugin logic if symbolic name is same as vendor id",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Bundle-DocURL": "http://www.google.com/",
|
||||
"Bundle-License": "http://www.apache.org/licenses/LICENSE-2.0.txt",
|
||||
"Bundle-ManifestVersion": "2",
|
||||
"Bundle-Name": "Google OAuth Client Library for Java",
|
||||
"Bundle-RequiredExecutionEnvironment": "JavaSE-1.6",
|
||||
"Bundle-SymbolicName": "com.google.oauth-client",
|
||||
"Bundle-Vendor": "Google",
|
||||
"Bundle-Version": "1.25.0",
|
||||
"Created-By": "Apache Maven Bundle Plugin",
|
||||
"Export-Package": "com.google.api.client.auth.openidconnect;uses:=\"com.google.api.client.auth.oauth2,com.google.api.client.json,com.google.api.client.json.webtoken,com.google.api.client.util\";version=\"1.25.0\",com.google.api.client.auth.oauth;uses:=\"com.google.api.client.http,com.google.api.client.util\";version=\"1.25.0\",com.google.api.client.auth.oauth2;uses:=\"com.google.api.client.http,com.google.api.client.json,com.google.api.client.util,com.google.api.client.util.store\";version=\"1.25.0\"",
|
||||
"Implementation-Title": "Google OAuth Client Library for Java",
|
||||
"Implementation-Vendor": "Google",
|
||||
"Implementation-Vendor-Id": "com.google.oauth-client",
|
||||
"Implementation-Version": "1.25.0",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Bundle-DocURL", Value: "http://www.google.com/"},
|
||||
{Key: "Bundle-License", Value: "http://www.apache.org/licenses/LICENSE-2.0.txt"},
|
||||
{Key: "Bundle-ManifestVersion", Value: "2"},
|
||||
{Key: "Bundle-Name", Value: "Google OAuth Client Library for Java"},
|
||||
{Key: "Bundle-RequiredExecutionEnvironment", Value: "JavaSE-1.6"},
|
||||
{Key: "Bundle-SymbolicName", Value: "com.google.oauth-client"},
|
||||
{Key: "Bundle-Vendor", Value: "Google"},
|
||||
{Key: "Bundle-Version", Value: "1.25.0"},
|
||||
{Key: "Created-By", Value: "Apache Maven Bundle Plugin"},
|
||||
{Key: "Export-Package", Value: "com.google.api.client.auth.openidconnect;uses:=\"com.google.api.client.auth.oauth2,com.google.api.client.json,com.google.api.client.json.webtoken,com.google.api.client.util\";version=\"1.25.0\",com.google.api.client.auth.oauth;uses:=\"com.google.api.client.http,com.google.api.client.util\";version=\"1.25.0\",com.google.api.client.auth.oauth2;uses:=\"com.google.api.client.http,com.google.api.client.json,com.google.api.client.util,com.google.api.client.util.store\";version=\"1.25.0\""},
|
||||
{Key: "Implementation-Title", Value: "Google OAuth Client Library for Java"},
|
||||
{Key: "Implementation-Vendor", Value: "Google"},
|
||||
{Key: "Implementation-Vendor-Id", Value: "com.google.oauth-client"},
|
||||
{Key: "Implementation-Version", Value: "1.25.0"},
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/google-oauth-client-1.25.0.jar"),
|
||||
@ -283,8 +352,11 @@ func TestSelectVersion(t *testing.T) {
|
||||
name: "Get name from Implementation-Version",
|
||||
archive: archiveFilename{},
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Implementation-Version": "1.8.2",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Implementation-Version",
|
||||
Value: "1.8.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "1.8.2",
|
||||
@ -292,9 +364,15 @@ func TestSelectVersion(t *testing.T) {
|
||||
{
|
||||
name: "Implementation-Version takes precedence over Specification-Version",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Implementation-Version": "1.8.2",
|
||||
"Specification-Version": "1.0",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Implementation-Version",
|
||||
Value: "1.8.2",
|
||||
},
|
||||
{
|
||||
Key: "Specification-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "1.8.2",
|
||||
@ -302,14 +380,15 @@ func TestSelectVersion(t *testing.T) {
|
||||
{
|
||||
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.)",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
{Key: "Ant-Version", Value: "Apache Ant 1.8.2"},
|
||||
{Key: "Created-By", Value: "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",
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{Key: "Name", Value: "org/apache/tools/ant/taskdefs/optional/"},
|
||||
{Key: "Implementation-Version", Value: "1.8.2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -318,34 +397,53 @@ func TestSelectVersion(t *testing.T) {
|
||||
{
|
||||
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",
|
||||
Main: pkg.KeyValues{
|
||||
{Key: "Manifest-Version", Value: "1.0"},
|
||||
{Key: "Ant-Version", Value: "Apache Ant 1.8.2"},
|
||||
{Key: "Created-By", Value: "1.5.0_22-b03 (Sun Microsystems Inc.)"},
|
||||
{Key: "Specification-Version", Value: "2.0"},
|
||||
},
|
||||
NamedSections: map[string]map[string]string{
|
||||
"org/apache/tools/ant/taskdefs/optional/": {
|
||||
"Specification-Version": "1.8",
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{Key: "Name", Value: "org/apache/tools/ant/taskdefs/optional/"},
|
||||
{Key: "Specification-Version", Value: "1.8"},
|
||||
},
|
||||
"some-other-section": {
|
||||
"Implementation-Version": "1.8.2",
|
||||
{
|
||||
{Key: "Name", Value: "some-other-section"},
|
||||
{Key: "Implementation-Version", Value: "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.)",
|
||||
Main: []pkg.KeyValue{
|
||||
{
|
||||
Key: "Manifest-Version",
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Key: "Ant-Version",
|
||||
Value: "Apache Ant 1.8.2",
|
||||
},
|
||||
{
|
||||
Key: "Created-By",
|
||||
Value: "1.5.0_22-b03 (Sun Microsystems Inc.)",
|
||||
},
|
||||
},
|
||||
NamedSections: map[string]map[string]string{
|
||||
"some-other-section": {
|
||||
"Bundle-Version": "1.11.28",
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "some-other-section",
|
||||
},
|
||||
{
|
||||
Key: "Bundle-Version",
|
||||
Value: "1.11.28",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -2,15 +2,15 @@ package pkg
|
||||
|
||||
// ConanLockEntry represents a single "node" entry from a conan.lock file.
|
||||
type ConanLockEntry struct {
|
||||
Ref string `json:"ref"`
|
||||
PackageID string `json:"package_id,omitempty"`
|
||||
Prev string `json:"prev,omitempty"`
|
||||
Requires []string `json:"requires,omitempty"`
|
||||
BuildRequires []string `json:"build_requires,omitempty"`
|
||||
PythonRequires []string `json:"py_requires,omitempty"`
|
||||
Options map[string]string `json:"options,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Context string `json:"context,omitempty"`
|
||||
Ref string `json:"ref"`
|
||||
PackageID string `json:"package_id,omitempty"`
|
||||
Prev string `json:"prev,omitempty"`
|
||||
Requires []string `json:"requires,omitempty"`
|
||||
BuildRequires []string `json:"build_requires,omitempty"`
|
||||
PythonRequires []string `json:"py_requires,omitempty"`
|
||||
Options KeyValues `json:"options,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Context string `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
// ConanfileEntry represents a single "Requires" entry from a conanfile.txt.
|
||||
|
||||
@ -2,12 +2,12 @@ package pkg
|
||||
|
||||
// GolangBinaryBuildinfoEntry represents all captured data for a Golang binary
|
||||
type GolangBinaryBuildinfoEntry struct {
|
||||
BuildSettings map[string]string `json:"goBuildSettings,omitempty" cyclonedx:"goBuildSettings"`
|
||||
GoCompiledVersion string `json:"goCompiledVersion" cyclonedx:"goCompiledVersion"`
|
||||
Architecture string `json:"architecture" cyclonedx:"architecture"`
|
||||
H1Digest string `json:"h1Digest,omitempty" cyclonedx:"h1Digest"`
|
||||
MainModule string `json:"mainModule,omitempty" cyclonedx:"mainModule"`
|
||||
GoCryptoSettings []string `json:"goCryptoSettings,omitempty" cyclonedx:"goCryptoSettings"`
|
||||
BuildSettings KeyValues `json:"goBuildSettings,omitempty" cyclonedx:"goBuildSettings"`
|
||||
GoCompiledVersion string `json:"goCompiledVersion" cyclonedx:"goCompiledVersion"`
|
||||
Architecture string `json:"architecture" cyclonedx:"architecture"`
|
||||
H1Digest string `json:"h1Digest,omitempty" cyclonedx:"h1Digest"`
|
||||
MainModule string `json:"mainModule,omitempty" cyclonedx:"mainModule"`
|
||||
GoCryptoSettings []string `json:"goCryptoSettings,omitempty" cyclonedx:"goCryptoSettings"`
|
||||
}
|
||||
|
||||
// GolangModuleEntry represents all captured data for a Golang source scan with go.mod/go.sum
|
||||
|
||||
@ -66,6 +66,15 @@ func (p JavaPomProperties) PkgTypeIndicated() Type {
|
||||
|
||||
// JavaManifest represents the fields of interest extracted from a Java archive's META-INF/MANIFEST.MF file.
|
||||
type JavaManifest struct {
|
||||
Main map[string]string `json:"main,omitempty"`
|
||||
NamedSections map[string]map[string]string `json:"namedSections,omitempty"`
|
||||
Main KeyValues `json:"main,omitempty"`
|
||||
Sections []KeyValues `json:"sections,omitempty"`
|
||||
}
|
||||
|
||||
func (m JavaManifest) Section(name string) KeyValues {
|
||||
for _, section := range m.Sections {
|
||||
if sectionName, ok := section.Get("Name"); ok && sectionName == name {
|
||||
return section
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
28
syft/pkg/key_value.go
Normal file
28
syft/pkg/key_value.go
Normal file
@ -0,0 +1,28 @@
|
||||
package pkg
|
||||
|
||||
type KeyValue struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type KeyValues []KeyValue
|
||||
|
||||
func (k KeyValues) Get(key string) (string, bool) {
|
||||
for _, kv := range k {
|
||||
if kv.Key == key {
|
||||
return kv.Value, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (k KeyValues) MustGet(key string) string {
|
||||
for _, kv := range k {
|
||||
if kv.Key == key {
|
||||
return kv.Value
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user