diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 1bae026b3e30..4bf6aa064999 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -69,7 +69,7 @@ trivy filesystem [flags] PATH --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --password-stdin password from stdin. Comma-separated passwords are not supported. - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 3c0c601b4c32..41bc6ce842bc 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -87,7 +87,7 @@ trivy image [flags] IMAGE_NAME --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --password-stdin password from stdin. Comma-separated passwords are not supported. - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --platform string set platform in the form os/arch if image is multi-platform capable --podman-host string unix podman socket path to use for podman scanning diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 0b342c28ea6e..9290ec0719b8 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -84,7 +84,7 @@ trivy kubernetes [flags] [CONTEXT] --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --password-stdin password from stdin. Comma-separated passwords are not supported. - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --qps float specify the maximum QPS to the master from this client (default 5) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 0567872e98ae..38ae6611b595 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -69,7 +69,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --password-stdin password from stdin. Comma-separated passwords are not supported. - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index f198187fb85d..b84dcc5cd2c3 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -71,7 +71,7 @@ trivy rootfs [flags] ROOTDIR --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --password-stdin password from stdin. Comma-separated passwords are not supported. - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 0419efece923..9456e8883532 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -49,7 +49,7 @@ trivy sbom [flags] SBOM_PATH --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --password-stdin password from stdin. Comma-separated passwords are not supported. - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 577a58b0f800..1074d878d866 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -61,7 +61,7 @@ trivy vm [flags] VM_IMAGE -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-relationships strings list of package relationships (unknown,root,workspace,direct,indirect) (default [unknown,root,workspace,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 56f77a14e888..365d2e5a57a9 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -447,6 +447,7 @@ pkg: relationships: - unknown - root + - workspace - direct - indirect diff --git a/integration/testdata/composer.lock.json.golden b/integration/testdata/composer.lock.json.golden index 5e2e49d8b965..00172acfdf53 100644 --- a/integration/testdata/composer.lock.json.golden +++ b/integration/testdata/composer.lock.json.golden @@ -26,7 +26,7 @@ "Name": "guzzlehttp/guzzle", "Identifier": { "PURL": "pkg:composer/guzzlehttp/guzzle@7.4.4", - "UID": "c26bf8868607a91c" + "UID": "b08c57e1706dce2d" }, "Version": "7.4.4", "Licenses": [ @@ -49,7 +49,7 @@ "Name": "guzzlehttp/psr7", "Identifier": { "PURL": "pkg:composer/guzzlehttp/psr7@1.8.3", - "UID": "1730859e3ff83ab9" + "UID": "75a904f2b589910f" }, "Version": "1.8.3", "Licenses": [ @@ -73,7 +73,7 @@ "PkgName": "guzzlehttp/psr7", "PkgIdentifier": { "PURL": "pkg:composer/guzzlehttp/psr7@1.8.3", - "UID": "1730859e3ff83ab9" + "UID": "75a904f2b589910f" }, "InstalledVersion": "1.8.3", "FixedVersion": "1.8.4", diff --git a/integration/testdata/conan.json.golden b/integration/testdata/conan.json.golden index d34caa079428..edc975f7a897 100644 --- a/integration/testdata/conan.json.golden +++ b/integration/testdata/conan.json.golden @@ -26,7 +26,7 @@ "Name": "poco", "Identifier": { "PURL": "pkg:conan/poco@1.9.4", - "UID": "312753cebe80c0eb" + "UID": "1c5e3b385e0d9c68" }, "Version": "1.9.4", "Relationship": "direct", @@ -50,7 +50,7 @@ "Name": "bzip2", "Identifier": { "PURL": "pkg:conan/bzip2@1.0.8", - "UID": "6e2ff993df2d9107" + "UID": "fcee910413ab7575" }, "Version": "1.0.8", "Indirect": true, @@ -68,7 +68,7 @@ "Name": "expat", "Identifier": { "PURL": "pkg:conan/expat@2.4.8", - "UID": "71c2d92d60f7f21c" + "UID": "1a3fe92a43620875" }, "Version": "2.4.8", "Indirect": true, @@ -86,7 +86,7 @@ "Name": "openssl", "Identifier": { "PURL": "pkg:conan/openssl@1.1.1q", - "UID": "13c605db6afa69dd" + "UID": "d009c32d2d560ed1" }, "Version": "1.1.1q", "Indirect": true, @@ -104,7 +104,7 @@ "Name": "pcre", "Identifier": { "PURL": "pkg:conan/pcre@8.43", - "UID": "4e01c692a67e12e4" + "UID": "452827dd216c920e" }, "Version": "8.43", "Indirect": true, @@ -126,7 +126,7 @@ "Name": "sqlite3", "Identifier": { "PURL": "pkg:conan/sqlite3@3.39.2", - "UID": "43bc9c58092c7c9e" + "UID": "8e926335e2fce900" }, "Version": "3.39.2", "Indirect": true, @@ -144,7 +144,7 @@ "Name": "zlib", "Identifier": { "PURL": "pkg:conan/zlib@1.2.12", - "UID": "d6faf8d6dfd1985" + "UID": "dfef9b967a82df9f" }, "Version": "1.2.12", "Indirect": true, @@ -165,7 +165,7 @@ "PkgName": "pcre", "PkgIdentifier": { "PURL": "pkg:conan/pcre@8.43", - "UID": "4e01c692a67e12e4" + "UID": "452827dd216c920e" }, "InstalledVersion": "8.43", "FixedVersion": "8.45", diff --git a/integration/testdata/gomod-skip.json.golden b/integration/testdata/gomod-skip.json.golden index 877fd627b89a..7c720157798c 100644 --- a/integration/testdata/gomod-skip.json.golden +++ b/integration/testdata/gomod-skip.json.golden @@ -27,7 +27,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "9d949a7b01249e68" + "UID": "782e16d5a74c9fa6" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", @@ -54,7 +54,7 @@ "PkgName": "github.com/open-policy-agent/opa", "PkgIdentifier": { "PURL": "pkg:golang/github.com/open-policy-agent/opa@v0.35.0", - "UID": "e89e2b0d8977e2a" + "UID": "3e43f458a7c60c10" }, "InstalledVersion": "v0.35.0", "FixedVersion": "0.37.0", @@ -101,7 +101,7 @@ "PkgName": "golang.org/x/text", "PkgIdentifier": { "PURL": "pkg:golang/golang.org/x/text@v0.3.6", - "UID": "3050088ce9eb2ce4" + "UID": "9c987ed7494d95be" }, "InstalledVersion": "v0.3.6", "FixedVersion": "0.3.7", @@ -134,7 +134,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "2f7f0fa81860b8f1" + "UID": "97673687db393443" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", diff --git a/integration/testdata/gomod-vex.json.golden b/integration/testdata/gomod-vex.json.golden index 34d96dc0ce95..dbe235013378 100644 --- a/integration/testdata/gomod-vex.json.golden +++ b/integration/testdata/gomod-vex.json.golden @@ -27,7 +27,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "9d949a7b01249e68" + "UID": "782e16d5a74c9fa6" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", @@ -54,7 +54,7 @@ "PkgName": "golang.org/x/text", "PkgIdentifier": { "PURL": "pkg:golang/golang.org/x/text@v0.3.6", - "UID": "3050088ce9eb2ce4" + "UID": "9c987ed7494d95be" }, "InstalledVersion": "v0.3.6", "FixedVersion": "0.3.7", @@ -87,7 +87,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "2f7f0fa81860b8f1" + "UID": "97673687db393443" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", @@ -121,7 +121,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "3ad40723ed2fce22" + "UID": "48e3a06649df4bd4" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", diff --git a/integration/testdata/gomod.json.golden b/integration/testdata/gomod.json.golden index 551b787cadd6..43249e07a9c7 100644 --- a/integration/testdata/gomod.json.golden +++ b/integration/testdata/gomod.json.golden @@ -27,7 +27,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "9d949a7b01249e68" + "UID": "782e16d5a74c9fa6" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", @@ -54,7 +54,7 @@ "PkgName": "github.com/open-policy-agent/opa", "PkgIdentifier": { "PURL": "pkg:golang/github.com/open-policy-agent/opa@v0.35.0", - "UID": "e89e2b0d8977e2a" + "UID": "3e43f458a7c60c10" }, "InstalledVersion": "v0.35.0", "FixedVersion": "0.37.0", @@ -101,7 +101,7 @@ "PkgName": "golang.org/x/text", "PkgIdentifier": { "PURL": "pkg:golang/golang.org/x/text@v0.3.6", - "UID": "3050088ce9eb2ce4" + "UID": "9c987ed7494d95be" }, "InstalledVersion": "v0.3.6", "FixedVersion": "0.3.7", @@ -134,7 +134,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "2f7f0fa81860b8f1" + "UID": "97673687db393443" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", @@ -168,7 +168,7 @@ "PkgName": "github.com/docker/distribution", "PkgIdentifier": { "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", - "UID": "3ad40723ed2fce22" + "UID": "48e3a06649df4bd4" }, "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", diff --git a/integration/testdata/nuget.json.golden b/integration/testdata/nuget.json.golden index b4ec872a839c..76fe3d706214 100644 --- a/integration/testdata/nuget.json.golden +++ b/integration/testdata/nuget.json.golden @@ -26,7 +26,7 @@ "Name": "Newtonsoft.Json", "Identifier": { "PURL": "pkg:nuget/Newtonsoft.Json@12.0.3", - "UID": "d4249b2442e303e9" + "UID": "1cec16ca9d4718aa" }, "Version": "12.0.3", "Relationship": "direct", @@ -43,7 +43,7 @@ "Name": "NuGet.Frameworks", "Identifier": { "PURL": "pkg:nuget/NuGet.Frameworks@5.7.0", - "UID": "6fa0c117039de82a" + "UID": "ed284c615e250d47" }, "Version": "5.7.0", "Relationship": "direct", @@ -66,7 +66,7 @@ "PkgName": "Newtonsoft.Json", "PkgIdentifier": { "PURL": "pkg:nuget/Newtonsoft.Json@12.0.3", - "UID": "d4249b2442e303e9" + "UID": "1cec16ca9d4718aa" }, "InstalledVersion": "12.0.3", "FixedVersion": "13.0.1", diff --git a/integration/testdata/pnpm.json.golden b/integration/testdata/pnpm.json.golden index 3edd379d10cb..6f8de4e57568 100644 --- a/integration/testdata/pnpm.json.golden +++ b/integration/testdata/pnpm.json.golden @@ -26,7 +26,7 @@ "Name": "jquery", "Identifier": { "PURL": "pkg:npm/jquery@3.3.9", - "UID": "53ca18565a4b6a47" + "UID": "2a8ffed0b32cf950" }, "Version": "3.3.9", "Licenses": [ @@ -40,7 +40,7 @@ "Name": "lodash", "Identifier": { "PURL": "pkg:npm/lodash@4.17.4", - "UID": "31eadfcf58a6b128" + "UID": "29795971f23e7bf6" }, "Version": "4.17.4", "Licenses": [ @@ -57,7 +57,7 @@ "PkgName": "jquery", "PkgIdentifier": { "PURL": "pkg:npm/jquery@3.3.9", - "UID": "53ca18565a4b6a47" + "UID": "2a8ffed0b32cf950" }, "InstalledVersion": "3.3.9", "FixedVersion": "3.4.0", @@ -190,7 +190,7 @@ "PkgName": "lodash", "PkgIdentifier": { "PURL": "pkg:npm/lodash@4.17.4", - "UID": "31eadfcf58a6b128" + "UID": "29795971f23e7bf6" }, "InstalledVersion": "4.17.4", "FixedVersion": "4.17.12", diff --git a/integration/testdata/poetry.json.golden b/integration/testdata/poetry.json.golden index 384c982876d3..916ec8e8e139 100644 --- a/integration/testdata/poetry.json.golden +++ b/integration/testdata/poetry.json.golden @@ -26,7 +26,7 @@ "Name": "click", "Identifier": { "PURL": "pkg:pypi/click@8.1.3", - "UID": "37edb5c90a97272e" + "UID": "d76da06fc75f0439" }, "Version": "8.1.3", "Relationship": "direct", @@ -40,7 +40,7 @@ "Name": "werkzeug", "Identifier": { "PURL": "pkg:pypi/werkzeug@0.14", - "UID": "4176be111ad01070" + "UID": "d14d05cca13c7a6b" }, "Version": "0.14", "Relationship": "direct", @@ -51,7 +51,7 @@ "Name": "colorama", "Identifier": { "PURL": "pkg:pypi/colorama@0.4.6", - "UID": "895013c17f373da3" + "UID": "c7ed705c1cc43242" }, "Version": "0.4.6", "Indirect": true, @@ -66,7 +66,7 @@ "PkgName": "werkzeug", "PkgIdentifier": { "PURL": "pkg:pypi/werkzeug@0.14", - "UID": "4176be111ad01070" + "UID": "d14d05cca13c7a6b" }, "InstalledVersion": "0.14", "FixedVersion": "0.15.3", diff --git a/integration/testdata/pom.json.golden b/integration/testdata/pom.json.golden index a583f02ce8e9..12bfa057e429 100644 --- a/integration/testdata/pom.json.golden +++ b/integration/testdata/pom.json.golden @@ -27,7 +27,7 @@ "PkgName": "com.fasterxml.jackson.core:jackson-databind", "PkgIdentifier": { "PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1", - "UID": "a704d87fd1c0b0e1" + "UID": "9c69fdeffb7ee6d4" }, "InstalledVersion": "2.9.1", "FixedVersion": "2.9.10.4", @@ -93,7 +93,7 @@ "PkgName": "com.fasterxml.jackson.core:jackson-databind", "PkgIdentifier": { "PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1", - "UID": "a704d87fd1c0b0e1" + "UID": "9c69fdeffb7ee6d4" }, "InstalledVersion": "2.9.1", "FixedVersion": "2.9.10.7", diff --git a/integration/testdata/pubspec.lock.json.golden b/integration/testdata/pubspec.lock.json.golden index a96211ac9119..cdbb89bf7b83 100644 --- a/integration/testdata/pubspec.lock.json.golden +++ b/integration/testdata/pubspec.lock.json.golden @@ -26,7 +26,7 @@ "Name": "http", "Identifier": { "PURL": "pkg:pub/http@0.13.2", - "UID": "b2aa9906ee615d4c" + "UID": "fe8339221b1b26b8" }, "Version": "0.13.2", "Relationship": "direct", @@ -37,7 +37,7 @@ "Name": "shelf", "Identifier": { "PURL": "pkg:pub/shelf@1.3.1", - "UID": "8367a65de5b4cda0" + "UID": "6d23c3a1f807b8ab" }, "Version": "1.3.1", "Indirect": true, @@ -52,7 +52,7 @@ "PkgName": "http", "PkgIdentifier": { "PURL": "pkg:pub/http@0.13.2", - "UID": "b2aa9906ee615d4c" + "UID": "fe8339221b1b26b8" }, "InstalledVersion": "0.13.2", "FixedVersion": "0.13.3", diff --git a/integration/testdata/yarn.json.golden b/integration/testdata/yarn.json.golden index 16b6c37584a1..c90131a428ed 100644 --- a/integration/testdata/yarn.json.golden +++ b/integration/testdata/yarn.json.golden @@ -26,7 +26,7 @@ "Name": "jquery", "Identifier": { "PURL": "pkg:npm/jquery@3.2.1", - "UID": "c7da6fd622178ea0" + "UID": "eab2410537cf8504" }, "Version": "3.2.1", "Licenses": [ @@ -49,7 +49,7 @@ "PkgName": "jquery", "PkgIdentifier": { "PURL": "pkg:npm/jquery@3.2.1", - "UID": "c7da6fd622178ea0" + "UID": "eab2410537cf8504" }, "InstalledVersion": "3.2.1", "FixedVersion": "3.4.0", diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 60a83ba9d81b..9f9afc35d99a 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -115,15 +115,18 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc // Cache root POM p.cache.put(result.artifact, result) - return p.parseRoot(root.artifact(), make(map[string]struct{})) + rootArt := root.artifact() + rootArt.Relationship = ftypes.RelationshipRoot + + return p.parseRoot(rootArt, make(map[string]struct{})) } +// nolint: gocyclo func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ftypes.Package, []ftypes.Dependency, error) { // Prepare a queue for dependencies queue := newArtifactQueue() // Enqueue root POM - root.Relationship = ftypes.RelationshipRoot root.Module = false queue.enqueue(root) @@ -166,7 +169,9 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft } // mark artifact as Direct, if saved artifact is Direct // take a look `hard requirement for the specified version` test - if uniqueArt.Relationship == ftypes.RelationshipRoot || uniqueArt.Relationship == ftypes.RelationshipDirect { + if uniqueArt.Relationship == ftypes.RelationshipRoot || + uniqueArt.Relationship == ftypes.RelationshipWorkspace || + uniqueArt.Relationship == ftypes.RelationshipDirect { art.Relationship = uniqueArt.Relationship } // We don't need to overwrite dependency location for hard links @@ -180,7 +185,7 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft return nil, nil, xerrors.Errorf("resolve error (%s): %w", art, err) } - if art.Relationship == ftypes.RelationshipRoot { + if art.Relationship == ftypes.RelationshipRoot || art.Relationship == ftypes.RelationshipWorkspace { // Managed dependencies in the root POM affect transitive dependencies rootDepManagement = p.resolveDepManagement(result.properties, result.dependencyManagement) @@ -243,6 +248,12 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft return packageID(dependOnName, ver), ver != "" }) + // `mvn` shows modules separately from the root package and does not show module nesting. + // So we can add all modules as dependencies of root package. + if art.Relationship == ftypes.RelationshipRoot { + dependsOn = append(dependsOn, lo.Keys(uniqModules)...) + } + sort.Strings(dependsOn) if len(dependsOn) > 0 { deps = append(deps, ftypes.Dependency{ @@ -279,7 +290,8 @@ func (p *Parser) parseModule(currentPath, relativePath string) (artifact, error) } moduleArtifact := module.artifact() - moduleArtifact.Module = true // TODO: introduce RelationshipModule? + moduleArtifact.Module = true + moduleArtifact.Relationship = ftypes.RelationshipWorkspace p.cache.put(moduleArtifact, result) diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 8d0bf002d6dc..eb1a7b6b9bb7 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -1214,7 +1214,7 @@ func TestPom_Parse(t *testing.T) { Name: "com.example:module", Version: "1.1.1", Licenses: []string{"Apache 2.0"}, - Relationship: ftypes.RelationshipRoot, // TODO: Several root modules break SBOM relationships + Relationship: ftypes.RelationshipWorkspace, }, { ID: "org.example:example-dependency:1.2.3", @@ -1230,24 +1230,15 @@ func TestPom_Parse(t *testing.T) { Relationship: ftypes.RelationshipIndirect, }, }, - // maven doesn't include modules in dep tree of root pom - // for modules uses separate graph: - // ➜ mvn dependency:tree - // [INFO] --------------------------------[ jar ]--------------------------------- - // [INFO] - // [INFO] --- dependency:3.6.0:tree (default-cli) @ module --- - // [INFO] com.example:module:jar:1.1.1 - // [INFO] \- org.example:example-dependency:jar:1.2.3:compile - // [INFO] \- org.example:example-api:jar:2.0.0:compile - // [INFO] - // [INFO] ----------------------< com.example:aggregation >----------------------- - // [INFO] Building aggregation 1.0.0 [2/2] - // [INFO] from pom.xml - // [INFO] --------------------------------[ pom ]--------------------------------- - // [INFO] - // [INFO] --- dependency:3.6.0:tree (default-cli) @ aggregation --- - // [INFO] com.example:aggregation:pom:1.0.0 + // `mvn` doesn't include modules in dep tree of root pom and builds separate graphs. + // But we have `root` and `workspace` relationships, so we can merge these graphs. wantDeps: []ftypes.Dependency{ + { + ID: "com.example:aggregation:1.0.0", + DependsOn: []string{ + "com.example:module:1.1.1", + }, + }, { ID: "com.example:module:1.1.1", DependsOn: []string{ @@ -1262,29 +1253,78 @@ func TestPom_Parse(t *testing.T) { }, }, }, + { + name: "nested modules", + inputFile: filepath.Join("testdata", "nested-modules", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:root:1.0.0", + Name: "com.example:root", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, + { + ID: "com.example:module1:1.0.0", + Name: "com.example:module1", + Version: "1.0.0", + Relationship: ftypes.RelationshipWorkspace, + }, + { + ID: "com.example:module2:2.0.0", + Name: "com.example:module2", + Version: "2.0.0", + Relationship: ftypes.RelationshipWorkspace, + }, + { + ID: "org.example:example-api:1.7.30", + Name: "org.example:example-api", + Version: "1.7.30", + Licenses: []string{ + "The Apache Software License, Version 2.0", + }, + Relationship: ftypes.RelationshipDirect, + }, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:module2:2.0.0", + DependsOn: []string{ + "org.example:example-api:1.7.30", + }, + }, + { + ID: "com.example:root:1.0.0", + DependsOn: []string{ + "com.example:module1:1.0.0", + "com.example:module2:2.0.0", + }, + }, + }, + }, { name: "Infinity loop for modules", inputFile: filepath.Join("testdata", "modules-infinity-loop", "pom.xml"), local: true, want: []ftypes.Package{ + { + ID: "org.example:root:1.0.0", + Name: "org.example:root", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, // as module { ID: "org.example:module-1:2.0.0", Name: "org.example:module-1", Version: "2.0.0", - Relationship: ftypes.RelationshipRoot, + Relationship: ftypes.RelationshipWorkspace, }, { ID: "org.example:module-2:3.0.0", Name: "org.example:module-2", Version: "3.0.0", - Relationship: ftypes.RelationshipRoot, // TODO: Several root modules break SBOM relationships - }, - { - ID: "org.example:root:1.0.0", - Name: "org.example:root", - Version: "1.0.0", - Relationship: ftypes.RelationshipRoot, // TODO: Several root modules break SBOM relationships + Relationship: ftypes.RelationshipWorkspace, }, // as dependency { @@ -1301,6 +1341,13 @@ func TestPom_Parse(t *testing.T) { "org.example:module-1:2.0.0", }, }, + { + ID: "org.example:root:1.0.0", + DependsOn: []string{ + "org.example:module-1:2.0.0", + "org.example:module-2:3.0.0", + }, + }, }, }, { @@ -1318,13 +1365,13 @@ func TestPom_Parse(t *testing.T) { ID: "com.example:module1:1.1.1", Name: "com.example:module1", Version: "1.1.1", - Relationship: ftypes.RelationshipRoot, + Relationship: ftypes.RelationshipWorkspace, }, { ID: "com.example:module2:1.1.1", Name: "com.example:module2", Version: "1.1.1", - Relationship: ftypes.RelationshipRoot, + Relationship: ftypes.RelationshipWorkspace, }, { ID: "org.example:example-api:1.7.30", @@ -1342,6 +1389,13 @@ func TestPom_Parse(t *testing.T) { }, }, wantDeps: []ftypes.Dependency{ + { + ID: "com.example:aggregation:1.0.0", + DependsOn: []string{ + "com.example:module1:1.1.1", + "com.example:module2:1.1.1", + }, + }, { ID: "com.example:module1:1.1.1", DependsOn: []string{ diff --git a/pkg/dependency/parser/java/pom/testdata/nested-modules/module1/module2/pom.xml b/pkg/dependency/parser/java/pom/testdata/nested-modules/module1/module2/pom.xml new file mode 100644 index 000000000000..16417a171747 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/nested-modules/module1/module2/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + + com.example + module2 + 2.0.0 + + pom + + + + org.example + example-api + 1.7.30 + + + diff --git a/pkg/dependency/parser/java/pom/testdata/nested-modules/module1/pom.xml b/pkg/dependency/parser/java/pom/testdata/nested-modules/module1/pom.xml new file mode 100644 index 000000000000..9e22eb6ba815 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/nested-modules/module1/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + + com.example + module1 + 1.0.0 + + pom + + + module2 + + diff --git a/pkg/dependency/parser/java/pom/testdata/nested-modules/pom.xml b/pkg/dependency/parser/java/pom/testdata/nested-modules/pom.xml new file mode 100644 index 000000000000..48d741859053 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/nested-modules/pom.xml @@ -0,0 +1,16 @@ + + 4.0.0 + + com.example + root + 1.0.0 + + pom + + + module1 + + + + diff --git a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden index 7c52aef32965..2ff8a71a1628 100644 --- a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden +++ b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden @@ -8,7 +8,7 @@ "Name": "dotenv", "Identifier": { "PURL": "pkg:gem/dotenv@2.7.2", - "UID": "bf323ef200ea177a" + "UID": "81de7d5923ef6698" }, "Version": "2.7.2", "Relationship": "direct", @@ -25,7 +25,7 @@ "Name": "faker", "Identifier": { "PURL": "pkg:gem/faker@1.9.3", - "UID": "b5ac01b24ab4ed39" + "UID": "8a05db8580a33fba" }, "Version": "1.9.3", "Relationship": "direct", @@ -45,7 +45,7 @@ "Name": "json", "Identifier": { "PURL": "pkg:gem/json@2.2.0", - "UID": "cb6c1eb54f8c6e9d" + "UID": "9d93d18f97484cf3" }, "Version": "2.2.0", "Relationship": "direct", @@ -62,7 +62,7 @@ "Name": "pry", "Identifier": { "PURL": "pkg:gem/pry@0.12.2", - "UID": "1349a1afdbbc80bc" + "UID": "7d01d0d732a91bb7" }, "Version": "0.12.2", "Relationship": "direct", @@ -83,7 +83,7 @@ "Name": "rails", "Identifier": { "PURL": "pkg:gem/rails@5.2.0", - "UID": "edef417a0d4c73e" + "UID": "21e56669bd72df57" }, "Version": "5.2.0", "Relationship": "direct", @@ -113,7 +113,7 @@ "Name": "rubocop", "Identifier": { "PURL": "pkg:gem/rubocop@0.67.2", - "UID": "68a7b25b67dfb858" + "UID": "957ab983044aa9f3" }, "Version": "0.67.2", "Relationship": "direct", @@ -139,7 +139,7 @@ "Name": "actioncable", "Identifier": { "PURL": "pkg:gem/actioncable@5.2.3", - "UID": "a2f0009734c47a50" + "UID": "ecd29a77dc997777" }, "Version": "5.2.3", "Indirect": true, @@ -162,7 +162,7 @@ "Name": "actionmailer", "Identifier": { "PURL": "pkg:gem/actionmailer@5.2.3", - "UID": "957dd2cc6d970211" + "UID": "b12f20a3315669b8" }, "Version": "5.2.3", "Indirect": true, @@ -187,7 +187,7 @@ "Name": "actionpack", "Identifier": { "PURL": "pkg:gem/actionpack@5.2.3", - "UID": "b4e4b4e5f7967b8a" + "UID": "3e6d8c3a4893cd5" }, "Version": "5.2.3", "Indirect": true, @@ -213,7 +213,7 @@ "Name": "actionview", "Identifier": { "PURL": "pkg:gem/actionview@5.2.3", - "UID": "e303cfc150443baf" + "UID": "3dcfe274dee232cf" }, "Version": "5.2.3", "Indirect": true, @@ -238,7 +238,7 @@ "Name": "activejob", "Identifier": { "PURL": "pkg:gem/activejob@5.2.3", - "UID": "107f18a1d47c926e" + "UID": "2c50cfba90b99d4f" }, "Version": "5.2.3", "Indirect": true, @@ -260,7 +260,7 @@ "Name": "activemodel", "Identifier": { "PURL": "pkg:gem/activemodel@5.2.3", - "UID": "22b9bacf4efb92d7" + "UID": "eefced6054bc7118" }, "Version": "5.2.3", "Indirect": true, @@ -281,7 +281,7 @@ "Name": "activerecord", "Identifier": { "PURL": "pkg:gem/activerecord@5.2.3", - "UID": "a30ec4dd4f1cad0d" + "UID": "54a0e498d3a27a9e" }, "Version": "5.2.3", "Indirect": true, @@ -304,7 +304,7 @@ "Name": "activestorage", "Identifier": { "PURL": "pkg:gem/activestorage@5.2.3", - "UID": "4e3f0e59a70b38a9" + "UID": "6b878767cc5bc16d" }, "Version": "5.2.3", "Indirect": true, @@ -327,7 +327,7 @@ "Name": "activesupport", "Identifier": { "PURL": "pkg:gem/activesupport@5.2.3", - "UID": "b83d5718f12b7df1" + "UID": "75237905ecef3213" }, "Version": "5.2.3", "Indirect": true, @@ -351,7 +351,7 @@ "Name": "arel", "Identifier": { "PURL": "pkg:gem/arel@9.0.0", - "UID": "9a68b51c670c5d28" + "UID": "2b27003c3d80c500" }, "Version": "9.0.0", "Indirect": true, @@ -369,7 +369,7 @@ "Name": "ast", "Identifier": { "PURL": "pkg:gem/ast@2.4.0", - "UID": "fad54f55dc524edc" + "UID": "7094963eecbb4a3a" }, "Version": "2.4.0", "Indirect": true, @@ -387,7 +387,7 @@ "Name": "builder", "Identifier": { "PURL": "pkg:gem/builder@3.2.3", - "UID": "4998ad08ac24b078" + "UID": "f47fc1abe3df2caa" }, "Version": "3.2.3", "Indirect": true, @@ -405,7 +405,7 @@ "Name": "coderay", "Identifier": { "PURL": "pkg:gem/coderay@1.1.2", - "UID": "a48fa0679d10835e" + "UID": "a912844ee6e547a5" }, "Version": "1.1.2", "Indirect": true, @@ -423,7 +423,7 @@ "Name": "concurrent-ruby", "Identifier": { "PURL": "pkg:gem/concurrent-ruby@1.1.5", - "UID": "bca3d9447a1c8032" + "UID": "1faccd8f356486f8" }, "Version": "1.1.5", "Indirect": true, @@ -441,7 +441,7 @@ "Name": "crass", "Identifier": { "PURL": "pkg:gem/crass@1.0.4", - "UID": "63d9762f8a29e52" + "UID": "aa66047c25aa8a3" }, "Version": "1.0.4", "Indirect": true, @@ -459,7 +459,7 @@ "Name": "erubi", "Identifier": { "PURL": "pkg:gem/erubi@1.8.0", - "UID": "de475f0ffcba457d" + "UID": "4f991bd1dc25f425" }, "Version": "1.8.0", "Indirect": true, @@ -477,7 +477,7 @@ "Name": "globalid", "Identifier": { "PURL": "pkg:gem/globalid@0.4.2", - "UID": "daff7877b36bd14b" + "UID": "7d42bb634d2ea5ca" }, "Version": "0.4.2", "Indirect": true, @@ -498,7 +498,7 @@ "Name": "i18n", "Identifier": { "PURL": "pkg:gem/i18n@1.6.0", - "UID": "66065208a829ff94" + "UID": "ff898062ba167e1a" }, "Version": "1.6.0", "Indirect": true, @@ -519,7 +519,7 @@ "Name": "jaro_winkler", "Identifier": { "PURL": "pkg:gem/jaro_winkler@1.5.2", - "UID": "9a5b22728e40960b" + "UID": "6a6b64429b52aaa8" }, "Version": "1.5.2", "Indirect": true, @@ -537,7 +537,7 @@ "Name": "loofah", "Identifier": { "PURL": "pkg:gem/loofah@2.2.3", - "UID": "61fc41b2f5521a64" + "UID": "370b8e0d823dff03" }, "Version": "2.2.3", "Indirect": true, @@ -559,7 +559,7 @@ "Name": "mail", "Identifier": { "PURL": "pkg:gem/mail@2.7.1", - "UID": "edee06a4b6e79f92" + "UID": "5e4c71169d7a349f" }, "Version": "2.7.1", "Indirect": true, @@ -580,7 +580,7 @@ "Name": "marcel", "Identifier": { "PURL": "pkg:gem/marcel@0.3.3", - "UID": "4695d691e0d7ac17" + "UID": "f43c52096c4ad09c" }, "Version": "0.3.3", "Indirect": true, @@ -601,7 +601,7 @@ "Name": "method_source", "Identifier": { "PURL": "pkg:gem/method_source@0.9.2", - "UID": "b96872ad7feeedb2" + "UID": "1fa86750277a95a3" }, "Version": "0.9.2", "Indirect": true, @@ -619,7 +619,7 @@ "Name": "mimemagic", "Identifier": { "PURL": "pkg:gem/mimemagic@0.3.3", - "UID": "54089ae8801a3144" + "UID": "a350af0aa168b20c" }, "Version": "0.3.3", "Indirect": true, @@ -637,7 +637,7 @@ "Name": "mini_mime", "Identifier": { "PURL": "pkg:gem/mini_mime@1.0.1", - "UID": "ea53b65af3f9c07c" + "UID": "ccc534b1135f68c9" }, "Version": "1.0.1", "Indirect": true, @@ -655,7 +655,7 @@ "Name": "mini_portile2", "Identifier": { "PURL": "pkg:gem/mini_portile2@2.4.0", - "UID": "503f9a3009616732" + "UID": "f3fa9c142de41168" }, "Version": "2.4.0", "Indirect": true, @@ -673,7 +673,7 @@ "Name": "minitest", "Identifier": { "PURL": "pkg:gem/minitest@5.11.3", - "UID": "1d1c12205a5ea0c1" + "UID": "37b0b09d82d19b2" }, "Version": "5.11.3", "Indirect": true, @@ -691,7 +691,7 @@ "Name": "nio4r", "Identifier": { "PURL": "pkg:gem/nio4r@2.3.1", - "UID": "1f214c910b2d6498" + "UID": "169da6540acc34de" }, "Version": "2.3.1", "Indirect": true, @@ -709,7 +709,7 @@ "Name": "nokogiri", "Identifier": { "PURL": "pkg:gem/nokogiri@1.10.3", - "UID": "4cadfe4426354933" + "UID": "a4dde592ac75f50b" }, "Version": "1.10.3", "Indirect": true, @@ -730,7 +730,7 @@ "Name": "parallel", "Identifier": { "PURL": "pkg:gem/parallel@1.17.0", - "UID": "f31aa3a8599717a1" + "UID": "ca10abfedb4b138b" }, "Version": "1.17.0", "Indirect": true, @@ -748,7 +748,7 @@ "Name": "parser", "Identifier": { "PURL": "pkg:gem/parser@2.6.3.0", - "UID": "fa2f74869e82d572" + "UID": "2bd5a2d3958a34d" }, "Version": "2.6.3.0", "Indirect": true, @@ -769,7 +769,7 @@ "Name": "psych", "Identifier": { "PURL": "pkg:gem/psych@3.1.0", - "UID": "34bd03308f382650" + "UID": "3b654c74c1c64d48" }, "Version": "3.1.0", "Indirect": true, @@ -787,7 +787,7 @@ "Name": "rack", "Identifier": { "PURL": "pkg:gem/rack@2.0.7", - "UID": "d9f77162d5199665" + "UID": "76cbaa6e040e1770" }, "Version": "2.0.7", "Indirect": true, @@ -805,7 +805,7 @@ "Name": "rack-test", "Identifier": { "PURL": "pkg:gem/rack-test@1.1.0", - "UID": "ce77144d56bbfcc7" + "UID": "cc4cf2b36612b845" }, "Version": "1.1.0", "Indirect": true, @@ -826,7 +826,7 @@ "Name": "rails-dom-testing", "Identifier": { "PURL": "pkg:gem/rails-dom-testing@2.0.3", - "UID": "f86753ba2b01f92d" + "UID": "51790bcbc34a4f9f" }, "Version": "2.0.3", "Indirect": true, @@ -848,7 +848,7 @@ "Name": "rails-html-sanitizer", "Identifier": { "PURL": "pkg:gem/rails-html-sanitizer@1.0.3", - "UID": "ca9d0e53040b92a7" + "UID": "3d074a9f84d5431a" }, "Version": "1.0.3", "Indirect": true, @@ -869,7 +869,7 @@ "Name": "railties", "Identifier": { "PURL": "pkg:gem/railties@5.2.3", - "UID": "79238ef7535ec96f" + "UID": "f4c2fc2260f590e8" }, "Version": "5.2.3", "Indirect": true, @@ -894,7 +894,7 @@ "Name": "rainbow", "Identifier": { "PURL": "pkg:gem/rainbow@3.0.0", - "UID": "b370837d83c44cb7" + "UID": "40028b39c319ccd6" }, "Version": "3.0.0", "Indirect": true, @@ -912,7 +912,7 @@ "Name": "rake", "Identifier": { "PURL": "pkg:gem/rake@12.3.2", - "UID": "4f4252bdb5e59b57" + "UID": "ad3a9cdaf7f45094" }, "Version": "12.3.2", "Indirect": true, @@ -930,7 +930,7 @@ "Name": "ruby-progressbar", "Identifier": { "PURL": "pkg:gem/ruby-progressbar@1.10.0", - "UID": "3955293b43d2fd52" + "UID": "2d6a80c63f6249f9" }, "Version": "1.10.0", "Indirect": true, @@ -948,7 +948,7 @@ "Name": "sprockets", "Identifier": { "PURL": "pkg:gem/sprockets@3.7.2", - "UID": "116e2747536e43f5" + "UID": "16df8dd119914f55" }, "Version": "3.7.2", "Indirect": true, @@ -970,7 +970,7 @@ "Name": "sprockets-rails", "Identifier": { "PURL": "pkg:gem/sprockets-rails@3.2.1", - "UID": "24b0c150e29c714e" + "UID": "3e708458a3535611" }, "Version": "3.2.1", "Indirect": true, @@ -993,7 +993,7 @@ "Name": "thor", "Identifier": { "PURL": "pkg:gem/thor@0.20.3", - "UID": "85877345b4057dc4" + "UID": "f2e43df8162dd43c" }, "Version": "0.20.3", "Indirect": true, @@ -1011,7 +1011,7 @@ "Name": "thread_safe", "Identifier": { "PURL": "pkg:gem/thread_safe@0.3.6", - "UID": "2851ab474c97947e" + "UID": "baaae7551e2b7a2d" }, "Version": "0.3.6", "Indirect": true, @@ -1029,7 +1029,7 @@ "Name": "tzinfo", "Identifier": { "PURL": "pkg:gem/tzinfo@1.2.5", - "UID": "1ef6e099466a3dd" + "UID": "b257df460b48c02e" }, "Version": "1.2.5", "Indirect": true, @@ -1050,7 +1050,7 @@ "Name": "unicode-display_width", "Identifier": { "PURL": "pkg:gem/unicode-display_width@1.5.0", - "UID": "5212ef154d81feeb" + "UID": "451db3c980d2abb2" }, "Version": "1.5.0", "Indirect": true, @@ -1068,7 +1068,7 @@ "Name": "websocket-driver", "Identifier": { "PURL": "pkg:gem/websocket-driver@0.7.0", - "UID": "6d4862fcfa71d8db" + "UID": "6c3ccfb2b719d633" }, "Version": "0.7.0", "Indirect": true, @@ -1089,7 +1089,7 @@ "Name": "websocket-extensions", "Identifier": { "PURL": "pkg:gem/websocket-extensions@0.1.3", - "UID": "84dd4f30cc911d14" + "UID": "9b87af4231c82ab8" }, "Version": "0.1.3", "Indirect": true, diff --git a/pkg/fanal/types/package.go b/pkg/fanal/types/package.go index 2726aa8ad8c8..340ad868b10d 100644 --- a/pkg/fanal/types/package.go +++ b/pkg/fanal/types/package.go @@ -16,6 +16,7 @@ type Relationship int const ( RelationshipUnknown Relationship = iota RelationshipRoot + RelationshipWorkspace // For maven `modules`. TODO use it for cargo and npm workspaces RelationshipDirect RelationshipIndirect ) @@ -24,6 +25,7 @@ var ( Relationships = []Relationship{ RelationshipUnknown, RelationshipRoot, + RelationshipWorkspace, RelationshipDirect, RelationshipIndirect, } @@ -31,6 +33,7 @@ var ( relationshipNames = [...]string{ "unknown", "root", + "workspace", "direct", "indirect", } diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 7b040f07d68b..93cdd2a9410c 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -765,6 +765,366 @@ func TestEncoder_Encode(t *testing.T) { }, wantVulns: make(map[uuid.UUID][]core.Vulnerability), }, + { + name: "multimodule maven project", + report: types.Report{ + SchemaVersion: 2, + ArtifactName: "pom.xml", + ArtifactType: artifact.TypeFilesystem, + Results: []types.Result{ + { + Target: "pom.xml", + Type: ftypes.Pom, + Class: types.ClassLangPkg, + Packages: []ftypes.Package{ + { + ID: "com.example:root:1.0.0", + Name: "com.example:root", + Version: "1.0.0", + Identifier: ftypes.PkgIdentifier{ + UID: "f684ec661900abbf", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "root", + Version: "1.0.0", + }, + }, + Relationship: ftypes.RelationshipRoot, + DependsOn: []string{ + "com.example:module1:1.0.0", + "com.example:module2:2.0.0", + }, + }, + { + ID: "com.example:module1:1.0.0", + Name: "com.example:module1", + Version: "1.0.0", + Identifier: ftypes.PkgIdentifier{ + UID: "ce0d29336874c431", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "module1", + Version: "1.0.0", + }, + }, + Relationship: ftypes.RelationshipWorkspace, + DependsOn: []string{ + "org.example:example-api:1.1.1", + }, + }, + { + ID: "com.example:module2:2.0.0", + Name: "com.example:module2", + Version: "2.0.0", + Identifier: ftypes.PkgIdentifier{ + UID: "387238ffef6dfa9d", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "module2", + Version: "2.0.0", + }, + }, + Relationship: ftypes.RelationshipWorkspace, + DependsOn: []string{ + "org.example:example-dependency:1.2.3", + }, + }, + { + ID: "org.example:example-api:1.1.1", + Name: "org.example:example-api", + Version: "1.1.1", + Identifier: ftypes.PkgIdentifier{ + UID: "45cdc62618708bb7", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.example", + Name: "example-api", + Version: "1.1.1", + }, + }, + Relationship: ftypes.RelationshipDirect, + }, + { + ID: "org.example:example-dependency:1.2.3", + Name: "org.example:example-dependency", + Version: "1.2.3", + Identifier: ftypes.PkgIdentifier{ + UID: "52fbe353a46651", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.example", + Name: "example-dependency", + Version: "1.2.3", + }, + }, + Relationship: ftypes.RelationshipDirect, + DependsOn: []string{ + "org.example:example-api:2.0.0", + }, + }, + { + ID: "org.example:example-api:2.0.0", + Name: "org.example:example-api", + Version: "2.0.0", + Identifier: ftypes.PkgIdentifier{ + UID: "f71d14b6d2bd8810", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.example", + Name: "example-api", + Version: "2.0.0", + }, + }, + Relationship: ftypes.RelationshipIndirect, + }, + }, + }, + }, + }, + wantComponents: map[uuid.UUID]*core.Component{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { + Type: core.TypeFilesystem, + Name: "pom.xml", + Root: true, + Properties: []core.Property{ + { + Name: core.PropertySchemaVersion, + Value: "2", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "3ff14136-e09f-4df9-80ea-000000000001", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): { + Type: core.TypeApplication, + Name: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyClass, + Value: "lang-pkgs", + }, + { + Name: core.PropertyType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + BOMRef: "3ff14136-e09f-4df9-80ea-000000000002", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000003"): { + Type: core.TypeLibrary, + Group: "com.example", + Name: "root", + Version: "1.0.0", + SrcFile: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyPkgID, + Value: "com.example:root:1.0.0", + }, + { + Name: core.PropertyPkgType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + UID: "f684ec661900abbf", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "root", + Version: "1.0.0", + }, + BOMRef: "pkg:maven/com.example/root@1.0.0", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000004"): { + Type: core.TypeLibrary, + Group: "com.example", + Name: "module1", + Version: "1.0.0", + SrcFile: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyPkgID, + Value: "com.example:module1:1.0.0", + }, + { + Name: core.PropertyPkgType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + UID: "ce0d29336874c431", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "module1", + Version: "1.0.0", + }, + BOMRef: "pkg:maven/com.example/module1@1.0.0", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000005"): { + Type: core.TypeLibrary, + Group: "com.example", + Name: "module2", + Version: "2.0.0", + SrcFile: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyPkgID, + Value: "com.example:module2:2.0.0", + }, + { + Name: core.PropertyPkgType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + UID: "387238ffef6dfa9d", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "module2", + Version: "2.0.0", + }, + BOMRef: "pkg:maven/com.example/module2@2.0.0", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000006"): { + Type: core.TypeLibrary, + Group: "org.example", + Name: "example-api", + Version: "1.1.1", + SrcFile: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyPkgID, + Value: "org.example:example-api:1.1.1", + }, + { + Name: core.PropertyPkgType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + UID: "45cdc62618708bb7", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.example", + Name: "example-api", + Version: "1.1.1", + }, + BOMRef: "pkg:maven/org.example/example-api@1.1.1", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000007"): { + Type: core.TypeLibrary, + Group: "org.example", + Name: "example-dependency", + Version: "1.2.3", + SrcFile: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyPkgID, + Value: "org.example:example-dependency:1.2.3", + }, + { + Name: core.PropertyPkgType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + UID: "52fbe353a46651", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.example", + Name: "example-dependency", + Version: "1.2.3", + }, + BOMRef: "pkg:maven/org.example/example-dependency@1.2.3", + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000008"): { + Type: core.TypeLibrary, + Group: "org.example", + Name: "example-api", + Version: "2.0.0", + SrcFile: "pom.xml", + Properties: []core.Property{ + { + Name: core.PropertyPkgID, + Value: "org.example:example-api:2.0.0", + }, + { + Name: core.PropertyPkgType, + Value: "pom", + }, + }, + PkgIdentifier: ftypes.PkgIdentifier{ + UID: "f71d14b6d2bd8810", + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.example", + Name: "example-api", + Version: "2.0.0", + }, + BOMRef: "pkg:maven/org.example/example-api@2.0.0", + }, + }, + }, + wantRels: map[uuid.UUID][]core.Relationship{ + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"), + Type: core.RelationshipContains, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000003"), + Type: core.RelationshipContains, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000003"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000004"), + Type: core.RelationshipDependsOn, + }, + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000005"), + Type: core.RelationshipDependsOn, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000004"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000006"), + Type: core.RelationshipDependsOn, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000005"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000007"), + Type: core.RelationshipDependsOn, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000006"): nil, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000007"): { + { + Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000008"), + Type: core.RelationshipDependsOn, + }, + }, + uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000008"): nil, + }, + wantVulns: make(map[uuid.UUID][]core.Vulnerability), + }, { name: "json file created from SBOM file (BOM is empty)", report: types.Report{