diff --git a/README.md b/README.md
index 19f6ca4b4..679e1c4a7 100644
--- a/README.md
+++ b/README.md
@@ -603,13 +603,15 @@ golang:
no-proxy: ""
java:
- # when running across pom.xml files that could have more information, syft will
- # explicitly search maven for license information by querying the online pom when this is true eg:
- # https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-test/3.1.5/spring-boot-starter-test-3.1.5.pom
- # this option is helpful for when the parent pom has this information,
- # but it is not accessible from within the final built artifact
- search-maven-for-licenses: false
maven-url: "https://repo1.maven.org/maven2"
+ max-parent-recursive-depth: 5
+ # enables Syft to use the network to fill in more detailed information about artifacts
+ # currently this enables searching maven-url for license data
+ # when running across pom.xml files that could have more information, syft will
+ # explicitly search maven for license information by querying the online pom when this is true
+ # this option is helpful for when the parent pom has more data,
+ # that is not accessible from within the final built artifact
+ use-network: false
linux-kernel:
# whether to catalog linux kernel modules found within lib/modules/** directories
diff --git a/cmd/syft/cli/options/catalog.go b/cmd/syft/cli/options/catalog.go
index 0848912cb..33395c45a 100644
--- a/cmd/syft/cli/options/catalog.go
+++ b/cmd/syft/cli/options/catalog.go
@@ -140,8 +140,9 @@ func (cfg Catalog) ToCatalogerConfig() cataloger.Config {
CatalogModules: cfg.LinuxKernel.CatalogModules,
},
Java: javaCataloger.DefaultCatalogerOpts().
- WithSearchMavenForLicenses(cfg.Java.SearchMavenForLicenses).
- WithMavenCentralURL(cfg.Java.MavenURL),
+ WithUseNetwork(cfg.Java.UseNetwork).
+ WithMavenCentralURL(cfg.Java.MavenURL).
+ WithMaxParentRecursiveDepth(cfg.Java.MaxParentRecursiveDepth),
Python: pythonCataloger.CatalogerConfig{
GuessUnpinnedRequirements: cfg.Python.GuessUnpinnedRequirements,
},
diff --git a/cmd/syft/cli/options/java.go b/cmd/syft/cli/options/java.go
index 4f1b76b16..7b7b9fd25 100644
--- a/cmd/syft/cli/options/java.go
+++ b/cmd/syft/cli/options/java.go
@@ -1,6 +1,7 @@
package options
type java struct {
- SearchMavenForLicenses bool `yaml:"search-maven-for-licenses" json:"search-maven-for-licenses" mapstructure:"search-maven-for-licenses"`
- MavenURL string `yaml:"maven-url" json:"maven-url" mapstructure:"maven-url"`
+ UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"`
+ MavenURL string `yaml:"maven-url" json:"maven-url" mapstructure:"maven-url"`
+ MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"`
}
diff --git a/syft/pkg/cataloger/config.go b/syft/pkg/cataloger/config.go
index f829bd113..3c283fee0 100644
--- a/syft/pkg/cataloger/config.go
+++ b/syft/pkg/cataloger/config.go
@@ -37,6 +37,7 @@ func (c Config) JavaConfig() java.Config {
return java.Config{
SearchUnindexedArchives: c.Search.IncludeUnindexedArchives,
SearchIndexedArchives: c.Search.IncludeIndexedArchives,
- SearchMavenForLicenses: c.Java.SearchMavenForLicenses,
+ UseNetwork: c.Java.UseNetwork,
+ MaxParentRecursiveDepth: c.Java.MaxParentRecursiveDepth,
}
}
diff --git a/syft/pkg/cataloger/java/archive_parser.go b/syft/pkg/cataloger/java/archive_parser.go
index 6653738db..109ea5bbc 100644
--- a/syft/pkg/cataloger/java/archive_parser.go
+++ b/syft/pkg/cataloger/java/archive_parser.go
@@ -286,8 +286,8 @@ func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (name, versi
if version == "" && pomProjectObject != nil {
version = pomProjectObject.Version
}
- if pomProjectObject != nil && j.cfg.SearchMavenForLicenses {
- findPomLicenses(pomProjectObject)
+ if pomProjectObject != nil && j.cfg.UseNetwork {
+ findPomLicenses(pomProjectObject, j.cfg)
}
if pomProjectObject != nil {
@@ -304,17 +304,20 @@ func artifactIDMatchesFilename(artifactID, fileName string) bool {
return strings.HasPrefix(artifactID, fileName) || strings.HasSuffix(fileName, artifactID)
}
-func findPomLicenses(pomProjectObject *parsedPomProject) {
+func findPomLicenses(pomProjectObject *parsedPomProject, cfg Config) {
// If we don't have any licenses until now, and if we have a parent Pom, then we'll check the parent pom in maven central for licenses.
if pomProjectObject != nil && pomProjectObject.Parent != nil && len(pomProjectObject.Licenses) == 0 {
- parentPom, err := getPomFromMavenCentral(pomProjectObject.Parent.GroupID, pomProjectObject.Parent.ArtifactID, pomProjectObject.Parent.Version)
+ parentLicenses, err := recursivelyFindLicensesFromParentPom(
+ pomProjectObject.Parent.GroupID,
+ pomProjectObject.Parent.ArtifactID,
+ pomProjectObject.Parent.Version,
+ cfg)
if err != nil {
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
log.Tracef("unable to get parent pom from Maven central: %v", err)
return
}
- parentLicenses := parseLicensesFromPom(parentPom)
- if len(parentLicenses) > 0 || parentPom == nil || parentPom.Parent == nil {
+ if len(parentLicenses) > 0 {
for _, licenseName := range parentLicenses {
pomProjectObject.Licenses = append(pomProjectObject.Licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
}
@@ -322,22 +325,44 @@ func findPomLicenses(pomProjectObject *parsedPomProject) {
}
}
-func formatMavenPomURL(groupID, artifactID, version string) (requestURL string, err error) {
+func formatMavenPomURL(groupID, artifactID, version, mavenBaseURL string) (requestURL string, err error) {
// groupID needs to go from maven.org -> maven/org
urlPath := strings.Split(groupID, ".")
artifactPom := fmt.Sprintf("%s-%s.pom", artifactID, version)
urlPath = append(urlPath, artifactID, version, artifactPom)
// ex:"https://repo1.maven.org/maven2/groupID/artifactID/artifactPom
- requestURL, err = url.JoinPath(MavenBaseURL, urlPath...)
+ requestURL, err = url.JoinPath(mavenBaseURL, urlPath...)
if err != nil {
return requestURL, fmt.Errorf("could not construct maven url: %w", err)
}
return requestURL, err
}
-func getPomFromMavenCentral(groupID, artifactID, version string) (*gopom.Project, error) {
- requestURL, err := formatMavenPomURL(groupID, artifactID, version)
+func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg Config) ([]string, error) {
+ var licenses []string
+ // As there can be nested parent poms, we'll recursively check for licenses until we reach the max depth
+ for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
+ parentPom, err := getPomFromMavenCentral(groupID, artifactID, version, cfg.MavenBaseURL)
+ if err != nil {
+ return nil, err
+ }
+ parentLicenses := parseLicensesFromPom(parentPom)
+ if len(parentLicenses) > 0 || parentPom == nil || parentPom.Parent == nil {
+ licenses = parentLicenses
+ break
+ }
+
+ groupID = *parentPom.Parent.GroupID
+ artifactID = *parentPom.Parent.ArtifactID
+ version = *parentPom.Parent.Version
+ }
+
+ return licenses, nil
+}
+
+func getPomFromMavenCentral(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
+ requestURL, err := formatMavenPomURL(groupID, artifactID, version, mavenBaseURL)
if err != nil {
return nil, err
}
diff --git a/syft/pkg/cataloger/java/archive_parser_test.go b/syft/pkg/cataloger/java/archive_parser_test.go
index 3d05fb868..9b48b34cd 100644
--- a/syft/pkg/cataloger/java/archive_parser_test.go
+++ b/syft/pkg/cataloger/java/archive_parser_test.go
@@ -4,6 +4,8 @@ import (
"bufio"
"fmt"
"io"
+ "net/http"
+ "net/http/httptest"
"os"
"os/exec"
"path/filepath"
@@ -44,6 +46,102 @@ func generateJavaBuildFixture(t *testing.T, fixturePath string) {
run(t, cmd)
}
+func generateMockMavenHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) {
+ return func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ // Set the Content-Type header to indicate that the response is XML
+ w.Header().Set("Content-Type", "application/xml")
+ // Copy the file's content to the response writer
+ file, err := os.Open(responseFixture)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ defer file.Close()
+ _, err = io.Copy(w, file)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }
+}
+
+type handlerPath struct {
+ path string
+ handler func(w http.ResponseWriter, r *http.Request)
+}
+
+func TestSearchMavenForLicenses(t *testing.T) {
+ mux, url, teardown := setup()
+ defer teardown()
+ tests := []struct {
+ name string
+ fixture string
+ detectNested bool
+ config Config
+ requestPath string
+ requestHandlers []handlerPath
+ expectedLicenses []pkg.License
+ }{
+ {
+ name: "searchMavenForLicenses returns the expected licenses when search is set to true",
+ fixture: "opensaml-core-3.4.6",
+ detectNested: false,
+ config: Config{
+ UseNetwork: true,
+ MavenBaseURL: url,
+ MaxParentRecursiveDepth: 2,
+ },
+ requestHandlers: []handlerPath{
+ {
+ path: "/org/opensaml/opensaml-parent/3.4.6/opensaml-parent-3.4.6.pom",
+ handler: generateMockMavenHandler("test-fixtures/maven-xml-responses/opensaml-parent-3.4.6.pom"),
+ },
+ {
+ path: "/net/shibboleth/parent/7.11.2/parent-7.11.2.pom",
+ handler: generateMockMavenHandler("test-fixtures/maven-xml-responses/parent-7.11.2.pom"),
+ },
+ },
+ expectedLicenses: []pkg.License{
+ {
+ Type: license.Declared,
+ Value: `The Apache Software License, Version 2.0`,
+ SPDXExpression: ``,
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ // configure maven central requests
+ for _, hdlr := range tc.requestHandlers {
+ mux.HandleFunc(hdlr.path, hdlr.handler)
+ }
+
+ // setup metadata fixture; note:
+ // this fixture has a pomProjectObject and has a parent object
+ // it has no licenses on either which is the condition for testing
+ // the searchMavenForLicenses functionality
+ jarName := generateJavaMetadataJarFixture(t, tc.fixture)
+ fixture, err := os.Open(jarName)
+ require.NoError(t, err)
+
+ // setup parser
+ ap, cleanupFn, err := newJavaArchiveParser(
+ file.LocationReadCloser{
+ Location: file.NewLocation(fixture.Name()),
+ ReadCloser: fixture,
+ }, tc.detectNested, tc.config)
+ defer cleanupFn()
+
+ // assert licenses are discovered from upstream
+ _, _, licenses := ap.guessMainPackageNameAndVersionFromPomInfo()
+ assert.Equal(t, tc.expectedLicenses, licenses)
+ })
+ }
+}
+
func TestFormatMavenURL(t *testing.T) {
tests := []struct {
name string
@@ -63,7 +161,7 @@ func TestFormatMavenURL(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
- requestURL, err := formatMavenPomURL(tc.groupID, tc.artifactID, tc.version)
+ requestURL, err := formatMavenPomURL(tc.groupID, tc.artifactID, tc.version, MavenBaseURL)
assert.NoError(t, err, "expected no err; got %w", err)
assert.Equal(t, tc.expected, requestURL)
})
@@ -303,7 +401,7 @@ func TestParseJar(t *testing.T) {
parser, cleanupFn, err := newJavaArchiveParser(file.LocationReadCloser{
Location: file.NewLocation(fixture.Name()),
ReadCloser: fixture,
- }, false, Config{SearchMavenForLicenses: false})
+ }, false, Config{UseNetwork: false})
defer cleanupFn()
require.NoError(t, err)
@@ -1303,3 +1401,21 @@ func run(t testing.TB, cmd *exec.Cmd) {
}
}
}
+
+// setup sets up a test HTTP server for mocking requests to maven central.
+// The returned url is injected into the Config so the client uses the test server.
+// Tests should register handlers on mux to simulate the expected request/response structure
+func setup() (mux *http.ServeMux, serverURL string, teardown func()) {
+ // mux is the HTTP request multiplexer used with the test server.
+ mux = http.NewServeMux()
+
+ // We want to ensure that tests catch mistakes where the endpoint URL is
+ // specified as absolute rather than relative. It only makes a difference
+ // when there's a non-empty base URL path. So, use that. See issue #752.
+ apiHandler := http.NewServeMux()
+ apiHandler.Handle("/", mux)
+ // server is a test HTTP server used to provide mock API responses.
+ server := httptest.NewServer(apiHandler)
+
+ return mux, server.URL, server.Close
+}
diff --git a/syft/pkg/cataloger/java/config.go b/syft/pkg/cataloger/java/config.go
index 07868ca91..bfa526f9b 100644
--- a/syft/pkg/cataloger/java/config.go
+++ b/syft/pkg/cataloger/java/config.go
@@ -3,6 +3,7 @@ package java
type Config struct {
SearchUnindexedArchives bool
SearchIndexedArchives bool
- SearchMavenForLicenses bool
+ UseNetwork bool
MavenBaseURL string
+ MaxParentRecursiveDepth int
}
diff --git a/syft/pkg/cataloger/java/options.go b/syft/pkg/cataloger/java/options.go
index c25a1d5ff..ddd19cd96 100644
--- a/syft/pkg/cataloger/java/options.go
+++ b/syft/pkg/cataloger/java/options.go
@@ -3,12 +3,13 @@ package java
const MavenBaseURL = "https://repo1.maven.org/maven2"
type CatalogerOpts struct {
- SearchMavenForLicenses bool
- MavenURL string
+ UseNetwork bool
+ MavenURL string
+ MaxParentRecursiveDepth int
}
-func (j CatalogerOpts) WithSearchMavenForLicenses(input bool) CatalogerOpts {
- j.SearchMavenForLicenses = input
+func (j CatalogerOpts) WithUseNetwork(input bool) CatalogerOpts {
+ j.UseNetwork = input
return j
}
@@ -19,9 +20,17 @@ func (j CatalogerOpts) WithMavenCentralURL(input string) CatalogerOpts {
return j
}
+func (j CatalogerOpts) WithMaxParentRecursiveDepth(input int) CatalogerOpts {
+ if input > 0 {
+ j.MaxParentRecursiveDepth = input
+ }
+ return j
+}
+
func DefaultCatalogerOpts() CatalogerOpts {
return CatalogerOpts{
- SearchMavenForLicenses: false,
- MavenURL: MavenBaseURL,
+ UseNetwork: false,
+ MavenURL: MavenBaseURL,
+ MaxParentRecursiveDepth: 5,
}
}
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile
index 1fd78b446..f837b37f2 100644
--- a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/Makefile
@@ -3,6 +3,7 @@ CACHE_PATH = $(shell pwd)/cache
JACKSON_CORE = jackson-core-2.15.2
SBT_JACKSON_CORE = com.fasterxml.jackson.core.jackson-core-2.15.2
+OPENSAML_CORE = opensaml-core-3.4.6
API_ALL_SOURCES = api-all-2.0.0-sources
$(CACHE_DIR):
@@ -14,5 +15,8 @@ $(CACHE_DIR)/$(JACKSON_CORE).jar: $(CACHE_DIR)
$(CACHE_DIR)/$(SBT_JACKSON_CORE).jar: $(CACHE_DIR)
cd $(SBT_JACKSON_CORE) && zip -r $(CACHE_PATH)/$(SBT_JACKSON_CORE).jar .
+$(CACHE_DIR)/$(OPENSAML_CORE).jar: $(CACHE_DIR)
+ cd $(OPENSAML_CORE) && zip -r $(CACHE_PATH)/$(OPENSAML_CORE).jar .
+
$(CACHE_DIR)/$(API_ALL_SOURCES).jar: $(CACHE_DIR)
cd $(API_ALL_SOURCES) && zip -r $(CACHE_PATH)/$(API_ALL_SOURCES).jar .
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/INDEX.LIST b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/INDEX.LIST
new file mode 100644
index 000000000..5378153c7
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/INDEX.LIST
@@ -0,0 +1,27 @@
+JarIndex-Version: 1.0
+
+opensaml-core-3.4.6.jar
+META-INF
+META-INF/maven
+META-INF/maven/org.opensaml
+META-INF/maven/org.opensaml/opensaml-core
+META-INF/services
+org
+org/opensaml
+org/opensaml/core
+org/opensaml/core/config
+org/opensaml/core/config/provider
+org/opensaml/core/criterion
+org/opensaml/core/metrics
+org/opensaml/core/metrics/impl
+org/opensaml/core/xml
+org/opensaml/core/xml/config
+org/opensaml/core/xml/io
+org/opensaml/core/xml/persist
+org/opensaml/core/xml/schema
+org/opensaml/core/xml/schema/impl
+org/opensaml/core/xml/util
+schema
+default-config.xml
+schema-config.xml
+
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/MANIFEST.MF b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..7ecbea6c9
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.opensaml.core
+Built-By: putmanb
+Build-Jdk: 1.7.0_80
+Created-By: Apache Maven 3.6.3
+Main-Class: org.opensaml.core.Version
+
+Name: org/opensaml/core/
+Implementation-Vendor: opensaml.org
+Implementation-Title: opensaml-core
+Implementation-Version: 3.4.6
+
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/maven/org.opensaml/opensaml-core/pom.properties b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/maven/org.opensaml/opensaml-core/pom.properties
new file mode 100644
index 000000000..7ddb6e110
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/maven/org.opensaml/opensaml-core/pom.properties
@@ -0,0 +1,4 @@
+#Created by Apache Maven 3.6.3
+version=3.4.6
+groupId=org.opensaml
+artifactId=opensaml-core
diff --git a/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/maven/org.opensaml/opensaml-core/pom.xml b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/maven/org.opensaml/opensaml-core/pom.xml
new file mode 100644
index 000000000..eab703e6e
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/jar-metadata/opensaml-core-3.4.6/META-INF/maven/org.opensaml/opensaml-core/pom.xml
@@ -0,0 +1,75 @@
+
+
+
+ 4.0.0
+
+
+ org.opensaml
+ opensaml-parent
+ 3.4.6
+ ../opensaml-parent
+
+
+ OpenSAML :: Core
+ Core
+ opensaml-core
+ jar
+
+
+ org.opensaml.core
+
+
+
+
+
+ joda-time
+ joda-time
+
+
+ io.dropwizard.metrics
+ metrics-core
+
+
+
+
+
+
+
+
+
+
+
+
+
+ maven-jar-plugin
+
+
+ true
+
+ org.opensaml.core.Version
+
+
+
+ org/opensaml/core/
+
+ ${project.artifactId}
+ ${project.version}
+ opensaml.org
+
+
+
+
+
+
+
+
+
+
+
+ site
+ dav:${opensaml-module.site.url}
+
+
+
+
diff --git a/syft/pkg/cataloger/java/test-fixtures/maven-xml-responses/opensaml-parent-3.4.6.pom b/syft/pkg/cataloger/java/test-fixtures/maven-xml-responses/opensaml-parent-3.4.6.pom
new file mode 100644
index 000000000..e3e2be465
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/maven-xml-responses/opensaml-parent-3.4.6.pom
@@ -0,0 +1,186 @@
+
+
+
+ 4.0.0
+
+
+ net.shibboleth
+ parent
+ 7.11.2
+
+
+ OpenSAML
+
+ A library for creating, reading, writing and performing some processing of SAML messages.
+
+ For further information see https://wiki.shibboleth.net/confluence/display/OS30/Home
+
+
+ org.opensaml
+ opensaml-parent
+ 3.4.6
+ pom
+
+
+ ../opensaml-core
+ ../opensaml-storage-api
+ ../opensaml-security-api
+ ../opensaml-xmlsec-api
+ ../opensaml-messaging-api
+ ../opensaml-soap-api
+ ../opensaml-saml-api
+ ../opensaml-xacml-api
+ ../opensaml-xacml-saml-api
+
+ ../opensaml-storage-impl
+ ../opensaml-security-impl
+ ../opensaml-xmlsec-impl
+ ../opensaml-messaging-impl
+ ../opensaml-soap-impl
+ ../opensaml-saml-impl
+ ../opensaml-xacml-impl
+ ../opensaml-xacml-saml-impl
+ ../opensaml-profile-api
+ ../opensaml-profile-impl
+
+ ../opensaml-bom
+ ../opensaml-tests-bom
+
+
+
+ 7.5.2
+ 5.4.2
+ ${project.basedir}/../opensaml-parent/resources/checkstyle/checkstyle.xml
+ ${shibboleth.site.url}java-opensaml/${project.version}/
+ ${opensaml-parent.site.url}${project.artifactId}
+
+
+
+
+
+
+
+
+ net.shibboleth.utilities
+ java-support
+ ${java-support.version}
+
+
+ commons-codec
+ commons-codec
+
+
+
+
+
+
+
+
+ net.shibboleth.utilities
+ java-support
+ ${java-support.version}
+ test-jar
+ test
+
+
+ org.xmlunit
+ xmlunit-legacy
+ test
+
+
+
+
+
+
+
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.1
+
+
+ org.hibernate
+ hibernate-entitymanager
+ 4.3.5.Final
+
+
+ xml-apis
+ xml-apis
+
+
+
+
+ org.hibernate.javax.persistence
+ hibernate-jpa-2.1-api
+ 1.0.0.Final
+
+
+ net.spy
+ spymemcached
+ 2.12.3
+
+
+
+
+
+
+
+
+ net.shibboleth.ext
+ spring-extensions
+ ${spring-extensions.version}
+ test
+
+
+
+
+
+
+ ${shibboleth.scm.connection}java-opensaml
+ ${shibboleth.scm.developerConnection}java-opensaml
+ ${shibboleth.scm.url}java-opensaml.git
+
+
+
+
+ site
+ dav:${opensaml-parent.site.url}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-site-plugin
+
+
+ attach-descriptor
+
+ attach-descriptor
+
+
+
+
+ ../opensaml-parent/src/site
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ ${automatic.module.name}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/syft/pkg/cataloger/java/test-fixtures/maven-xml-responses/parent-7.11.2.pom b/syft/pkg/cataloger/java/test-fixtures/maven-xml-responses/parent-7.11.2.pom
new file mode 100644
index 000000000..a6e4da926
--- /dev/null
+++ b/syft/pkg/cataloger/java/test-fixtures/maven-xml-responses/parent-7.11.2.pom
@@ -0,0 +1,118 @@
+
+
+
+ 4.0.0
+
+ net.shibboleth
+ parent
+ 7.11.2
+ pom
+
+ Shibboleth Project V3 Super POM
+
+ A POM containing properties, profiles, plugin configurations, etc. that are common across all Shibboleth V3 projects.
+
+
+
+ UTF-8
+ 1.7
+ 1.7
+
+ 1.59
+ 1.1.4
+
+ org.apache.httpcomponents
+ 4.5.13
+ 4.4.14
+ 20.0
+ org.eclipse.jetty
+ 9.2.14.v20151106
+ 1.0.13
+ 1.2.3
+ 3.1.5
+ 2.10.4
+ org.slf4j
+ 1.7.30
+ org.springframework
+ 4.3.30.RELEASE
+ org.springframework.webflow
+ 2.4.8.RELEASE
+ 2.0.10
+ 2.5.1
+
+ 8.26
+ 3.1.0
+ checkstyle.xml
+
+ 3.0.0
+
+ https://repo1.maven.org/maven2
+ https://build.shibboleth.net/nexus/content/sites/site/
+
+ scm:git:https://git.shibboleth.net/git/
+ scm:git:git@git.shibboleth.net:
+ https://git.shibboleth.net/view/?p=
+
+
+
+
+
+ 3.3.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ http://shibboleth.net/
+
+ 1999
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+
+
+
+
+
+
+ ${shibboleth.scm.connection}java-parent-project-v3
+ ${shibboleth.scm.developerConnection}java-parent-project-v3
+ ${shibboleth.scm.url}java-parent-project-v3.git
+
+
+
+
+
+
+
+
+
+
+