fix: bad pom files may cause infinite loop (#3391)

Signed-off-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
Keith Zantow 2024-10-28 18:09:04 -04:00 committed by GitHub
parent 55cc1877ef
commit 1118ac4ace
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 77 additions and 5 deletions

View File

@ -135,9 +135,14 @@ func (r *Resolver) resolveProperty(ctx context.Context, resolutionContext []*Pro
return value, nil return value, nil
} }
var resolvingParents []*Project
for _, pom := range resolutionContext { for _, pom := range resolutionContext {
current := pom current := pom
for parentDepth := 0; current != nil; parentDepth++ { for parentDepth := 0; current != nil; parentDepth++ {
if slices.Contains(resolvingParents, current) {
log.WithFields("property", propertyExpression, "mavenID", r.resolveID(ctx, resolvingProperties, resolvingParents...)).Error("got circular reference while resolving property")
break // some sort of circular reference -- we've already seen this project
}
if r.cfg.MaxParentRecursiveDepth > 0 && parentDepth > r.cfg.MaxParentRecursiveDepth { if r.cfg.MaxParentRecursiveDepth > 0 && parentDepth > r.cfg.MaxParentRecursiveDepth {
return "", fmt.Errorf("maximum parent recursive depth (%v) reached resolving property: %v", r.cfg.MaxParentRecursiveDepth, propertyExpression) return "", fmt.Errorf("maximum parent recursive depth (%v) reached resolving property: %v", r.cfg.MaxParentRecursiveDepth, propertyExpression)
} }
@ -146,6 +151,7 @@ func (r *Resolver) resolveProperty(ctx context.Context, resolutionContext []*Pro
return r.resolveExpression(ctx, resolutionContext, value, resolvingProperties) // property values can contain expressions return r.resolveExpression(ctx, resolutionContext, value, resolvingProperties) // property values can contain expressions
} }
} }
resolvingParents = append(resolvingParents, current)
current, err = r.resolveParent(ctx, current, resolvingProperties...) current, err = r.resolveParent(ctx, current, resolvingProperties...)
if err != nil { if err != nil {
return "", err return "", err
@ -271,13 +277,12 @@ func (r *Resolver) resolveID(ctx context.Context, resolvingProperties []string,
artifactID := r.resolvePropertyValue(ctx, pom.ArtifactID, resolvingProperties, resolutionContext...) artifactID := r.resolvePropertyValue(ctx, pom.ArtifactID, resolvingProperties, resolutionContext...)
version := r.resolvePropertyValue(ctx, pom.Version, resolvingProperties, resolutionContext...) version := r.resolvePropertyValue(ctx, pom.Version, resolvingProperties, resolutionContext...)
if pom.Parent != nil { if pom.Parent != nil {
if groupID == "" { // groupId and version are able to be inherited from the parent, but importantly: not artifactId. see:
// https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#the-solution
if groupID == "" && deref(pom.GroupID) == "" {
groupID = r.resolvePropertyValue(ctx, pom.Parent.GroupID, resolvingProperties, resolutionContext...) groupID = r.resolvePropertyValue(ctx, pom.Parent.GroupID, resolvingProperties, resolutionContext...)
} }
if artifactID == "" { if version == "" && deref(pom.Version) == "" {
artifactID = r.resolvePropertyValue(ctx, pom.Parent.ArtifactID, resolvingProperties, resolutionContext...)
}
if version == "" {
version = r.resolvePropertyValue(ctx, pom.Parent.Version, resolvingProperties, resolutionContext...) version = r.resolvePropertyValue(ctx, pom.Parent.Version, resolvingProperties, resolutionContext...)
} }
} }

View File

@ -243,6 +243,13 @@ func Test_mavenResolverRemote(t *testing.T) {
expression: "${project.one}", expression: "${project.one}",
expected: "1", expected: "1",
}, },
{
groupID: "my.org", // this particular package has a circular reference
artifactID: "circular",
version: "1.2.3",
expression: "${unresolved}",
expected: "",
},
} }
for _, test := range tests { for _, test := range tests {
@ -312,6 +319,27 @@ func Test_relativePathParent(t *testing.T) {
require.Equal(t, "", id.Version) require.Equal(t, "", id.Version)
}, },
}, },
{
name: "circular resolving ID variables",
pom: "circular-1/pom.xml",
validate: func(t *testing.T, r *Resolver, pom *Project) {
require.NotNil(t, pom)
id := r.ResolveID(ctx, pom)
// version should be resolved, but not artifactId
require.Equal(t, "1.2.3", id.Version)
require.Equal(t, "", id.ArtifactID)
},
},
{
name: "circular parent only",
pom: "circular-2/pom.xml",
validate: func(t *testing.T, r *Resolver, pom *Project) {
require.NotNil(t, pom)
id := r.ResolveID(ctx, pom)
require.Equal(t, "", id.Version)
require.Equal(t, "something", id.ArtifactID)
},
},
} }
for _, test := range tests { for _, test := range tests {

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<parent>
<groupId>my.org</groupId>
<artifactId>circular</artifactId>
<version>1.2.3</version>
</parent>
</project>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>something</artifactId>
<version>${unresolvable}</version>
<parent>
<groupId>my.org</groupId>
<artifactId>circular</artifactId>
<version>1.2.3</version>
</parent>
</project>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>circular</artifactId>
<version>1.2.3</version>
<parent>
<groupId>my.org</groupId>
<artifactId>circular</artifactId>
<version>1.2.3</version>
</parent>
</project>