diff --git a/go.mod b/go.mod
index 7e5fb03d..ddacf6e7 100644
--- a/go.mod
+++ b/go.mod
@@ -7,15 +7,16 @@ require (
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492
github.com/hashicorp/go-multierror v1.1.1
- github.com/hashicorp/go-retryablehttp v0.7.4
+ github.com/hashicorp/go-retryablehttp v0.7.5
github.com/liamg/jfather v0.0.7
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032
github.com/samber/lo v1.38.1
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4
- golang.org/x/mod v0.13.0
- golang.org/x/net v0.17.0
+ golang.org/x/mod v0.14.0
+ golang.org/x/net v0.18.0
+ golang.org/x/text v0.14.0
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
gopkg.in/yaml.v3 v3.0.1
)
@@ -26,5 +27,4 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
- golang.org/x/text v0.13.0 // indirect
)
diff --git a/go.sum b/go.sum
index 74abe090..80823fb7 100644
--- a/go.sum
+++ b/go.sum
@@ -17,8 +17,8 @@ github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxC
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
-github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
+github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
+github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/liamg/jfather v0.0.7 h1:Xf78zS263yfT+xr2VSo6+kyAy4ROlCacRqJG7s5jt4k=
github.com/liamg/jfather v0.0.7/go.mod h1:xXBGiBoiZ6tmHhfy5Jzw8sugzajwYdi6VosIpB3/cPM=
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 h1:TLygBUBxikNJJfLwgm+Qwdgq1FtfV8Uh7bcxRyTzK8s=
@@ -43,12 +43,12 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4 h1:K3x+yU+fbot38x5bQbU2QqUAVyYLEktdNH2GxZLnM3U=
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
-golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
-golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
+golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
diff --git a/pkg/java/pom/parse.go b/pkg/java/pom/parse.go
index e2de5094..9e8fe900 100644
--- a/pkg/java/pom/parse.go
+++ b/pkg/java/pom/parse.go
@@ -510,6 +510,15 @@ func (p *parser) tryRelativePath(parentArtifact artifact, currentPath, relativeP
return nil, err
}
+ // To avoid an infinite loop or parsing the wrong parent when using relatedPath or `../pom.xml`,
+ // we need to compare GAV of `parentArtifact` (`parent` tag from base pom) and GAV of pom from `relativePath`.
+ // See `compare ArtifactIDs for base and parent pom's` test for example.
+ // But GroupID can be inherited from parent (`p.analyze` function is required to get the GroupID).
+ // Version can contain a property (`p.analyze` function is required to get the GroupID).
+ // So we can only match ArtifactID's.
+ if pom.artifact().ArtifactID != parentArtifact.ArtifactID {
+ return nil, xerrors.New("'parent.relativePath' points at wrong local POM")
+ }
result, err := p.analyze(pom, analysisOptions{})
if err != nil {
return nil, xerrors.Errorf("analyze error: %w", err)
diff --git a/pkg/java/pom/parse_test.go b/pkg/java/pom/parse_test.go
index 36fdd84e..398e9ade 100644
--- a/pkg/java/pom/parse_test.go
+++ b/pkg/java/pom/parse_test.go
@@ -984,6 +984,19 @@ func TestPom_Parse(t *testing.T) {
},
},
},
+ {
+ name: "compare ArtifactIDs for base and parent pom's",
+ inputFile: filepath.Join("testdata", "no-parent-infinity-loop", "pom.xml"),
+ local: true,
+ want: []types.Library{
+ {
+ ID: "com.example:child:1.0.0",
+ Name: "com.example:child",
+ Version: "1.0.0",
+ License: "The Apache Software License, Version 2.0",
+ },
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/pkg/java/pom/testdata/no-parent-infinity-loop/parent/pom.xml b/pkg/java/pom/testdata/no-parent-infinity-loop/parent/pom.xml
new file mode 100644
index 00000000..0af9c80e
--- /dev/null
+++ b/pkg/java/pom/testdata/no-parent-infinity-loop/parent/pom.xml
@@ -0,0 +1,19 @@
+
+ 4.0.0
+
+ com.example
+ parent
+ 1.0.0
+
+ pom
+ parent
+ Parent
+
+
+ org.example
+ example-api
+ 1.7.30
+
+
+
diff --git a/pkg/java/pom/testdata/no-parent-infinity-loop/pom.xml b/pkg/java/pom/testdata/no-parent-infinity-loop/pom.xml
new file mode 100644
index 00000000..f2c9bfb7
--- /dev/null
+++ b/pkg/java/pom/testdata/no-parent-infinity-loop/pom.xml
@@ -0,0 +1,17 @@
+
+ 4.0.0
+
+ child
+
+ child
+ Child
+
+
+ com.example
+ parent
+ 1.0.0
+ ./parent
+
+
+
diff --git a/pkg/java/pom/testdata/parent-child-properties/parent/pom.xml b/pkg/java/pom/testdata/parent-child-properties/parent/pom.xml
index b51bee75..5ec3c450 100644
--- a/pkg/java/pom/testdata/parent-child-properties/parent/pom.xml
+++ b/pkg/java/pom/testdata/parent-child-properties/parent/pom.xml
@@ -4,7 +4,7 @@
com.example
- parent
+ top-parent
1.0.0
../top-parent
diff --git a/pkg/nuget/packagesprops/parse.go b/pkg/nuget/packagesprops/parse.go
new file mode 100644
index 00000000..995364a6
--- /dev/null
+++ b/pkg/nuget/packagesprops/parse.go
@@ -0,0 +1,85 @@
+package packagesprops
+
+import (
+ "encoding/xml"
+ "strings"
+
+ "golang.org/x/xerrors"
+
+ dio "github.com/aquasecurity/go-dep-parser/pkg/io"
+ "github.com/aquasecurity/go-dep-parser/pkg/types"
+ "github.com/aquasecurity/go-dep-parser/pkg/utils"
+)
+
+type pkg struct {
+ Version string `xml:"Version,attr"`
+ UpdatePackageName string `xml:"Update,attr"`
+ IncludePackageName string `xml:"Include,attr"`
+}
+
+// https://github.com/dotnet/roslyn-tools/blob/b4c5220f5dfc4278847b6d38eff91cc1188f8066/src/RoslynInsertionTool/RoslynInsertionTool/CoreXT.cs#L150
+type itemGroup struct {
+ PackageReferenceEntry []pkg `xml:"PackageReference"`
+ PackageVersionEntry []pkg `xml:"PackageVersion"`
+}
+
+type project struct {
+ XMLName xml.Name `xml:"Project"`
+ ItemGroups []itemGroup `xml:"ItemGroup"`
+}
+
+type Parser struct{}
+
+func NewParser() types.Parser {
+ return &Parser{}
+}
+
+func (p pkg) library() types.Library {
+ // Update attribute is considered legacy, so preferring Include
+ name := p.UpdatePackageName
+ if p.IncludePackageName != "" {
+ name = p.IncludePackageName
+ }
+
+ name = strings.TrimSpace(name)
+ version := strings.TrimSpace(p.Version)
+ return types.Library{
+ ID: utils.PackageID(name, version),
+ Name: name,
+ Version: version,
+ }
+}
+
+func shouldSkipLib(lib types.Library) bool {
+ if len(lib.Name) == 0 || len(lib.Version) == 0 {
+ return true
+ }
+ // *packages.props files don't contain variable resolution information.
+ // So we need to skip them.
+ if isVariable(lib.Name) || isVariable(lib.Version) {
+ return true
+ }
+ return false
+}
+
+func isVariable(s string) bool {
+ return strings.HasPrefix(s, "$(") && strings.HasSuffix(s, ")")
+}
+
+func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) {
+ var configData project
+ if err := xml.NewDecoder(r).Decode(&configData); err != nil {
+ return nil, nil, xerrors.Errorf("failed to decode '*.packages.props' file: %w", err)
+ }
+
+ var libs []types.Library
+ for _, item := range configData.ItemGroups {
+ for _, pkg := range append(item.PackageReferenceEntry, item.PackageVersionEntry...) {
+ lib := pkg.library()
+ if !shouldSkipLib(lib) {
+ libs = append(libs, lib)
+ }
+ }
+ }
+ return utils.UniqueLibraries(libs), nil, nil
+}
diff --git a/pkg/nuget/packagesprops/parse_test.go b/pkg/nuget/packagesprops/parse_test.go
new file mode 100644
index 00000000..56318f74
--- /dev/null
+++ b/pkg/nuget/packagesprops/parse_test.go
@@ -0,0 +1,82 @@
+package packagesprops_test
+
+import (
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ config "github.com/aquasecurity/go-dep-parser/pkg/nuget/packagesprops"
+ "github.com/aquasecurity/go-dep-parser/pkg/types"
+)
+
+func TestParse(t *testing.T) {
+ tests := []struct {
+ name string // Test input file
+ inputFile string
+ want []types.Library
+ wantErr string
+ }{
+ {
+ name: "PackagesProps",
+ inputFile: "testdata/packages.props",
+ want: []types.Library{
+ {Name: "Microsoft.Extensions.Configuration", Version: "2.1.1", ID: "Microsoft.Extensions.Configuration@2.1.1"},
+ {Name: "Microsoft.Extensions.DependencyInjection.Abstractions", Version: "2.2.1", ID: "Microsoft.Extensions.DependencyInjection.Abstractions@2.2.1"},
+ {Name: "Microsoft.Extensions.Http", Version: "3.2.1", ID: "Microsoft.Extensions.Http@3.2.1"},
+ },
+ },
+ {
+ name: "DirectoryPackagesProps",
+ inputFile: "testdata/Directory.Packages.props",
+ want: []types.Library{
+ {Name: "PackageOne", Version: "6.2.3", ID: "PackageOne@6.2.3"},
+ {Name: "PackageThree", Version: "2.4.1", ID: "PackageThree@2.4.1"},
+ {Name: "PackageTwo", Version: "6.0.0", ID: "PackageTwo@6.0.0"},
+ },
+ },
+ {
+ name: "SeveralItemGroupElements",
+ inputFile: "testdata/several_item_groups",
+ want: []types.Library{
+ {Name: "PackageOne", Version: "6.2.3", ID: "PackageOne@6.2.3"},
+ {Name: "PackageThree", Version: "2.4.1", ID: "PackageThree@2.4.1"},
+ {Name: "PackageTwo", Version: "6.0.0", ID: "PackageTwo@6.0.0"},
+ },
+ },
+ {
+ name: "VariablesAsNamesOrVersion",
+ inputFile: "testdata/variables_and_empty",
+ want: []types.Library{
+ {Name: "PackageFour", Version: "2.4.1", ID: "PackageFour@2.4.1"},
+ },
+ },
+ {
+ name: "NoItemGroupInXMLStructure",
+ inputFile: "testdata/no_item_group.props",
+ want: []types.Library(nil),
+ },
+ {
+ name: "NoProject",
+ inputFile: "testdata/no_project.props",
+ wantErr: "failed to decode '*.packages.props' file",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ f, err := os.Open(tt.inputFile)
+ require.NoError(t, err)
+
+ got, _, err := config.NewParser().Parse(f)
+ if tt.wantErr != "" {
+ require.NotNil(t, err)
+ assert.Contains(t, err.Error(), tt.wantErr)
+ return
+ }
+
+ assert.NoError(t, err)
+ assert.Equal(t, tt.want, got)
+ })
+ }
+}
diff --git a/pkg/nuget/packagesprops/testdata/Directory.Packages.props b/pkg/nuget/packagesprops/testdata/Directory.Packages.props
new file mode 100644
index 00000000..62c085ba
--- /dev/null
+++ b/pkg/nuget/packagesprops/testdata/Directory.Packages.props
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pkg/nuget/packagesprops/testdata/no_item_group.props b/pkg/nuget/packagesprops/testdata/no_item_group.props
new file mode 100644
index 00000000..aa3b2813
--- /dev/null
+++ b/pkg/nuget/packagesprops/testdata/no_item_group.props
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pkg/nuget/packagesprops/testdata/no_project.props b/pkg/nuget/packagesprops/testdata/no_project.props
new file mode 100644
index 00000000..041498a6
--- /dev/null
+++ b/pkg/nuget/packagesprops/testdata/no_project.props
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pkg/nuget/packagesprops/testdata/packages.props b/pkg/nuget/packagesprops/testdata/packages.props
new file mode 100644
index 00000000..7ec6d02a
--- /dev/null
+++ b/pkg/nuget/packagesprops/testdata/packages.props
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pkg/nuget/packagesprops/testdata/several_item_groups b/pkg/nuget/packagesprops/testdata/several_item_groups
new file mode 100644
index 00000000..1575af4a
--- /dev/null
+++ b/pkg/nuget/packagesprops/testdata/several_item_groups
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pkg/nuget/packagesprops/testdata/variables_and_empty b/pkg/nuget/packagesprops/testdata/variables_and_empty
new file mode 100644
index 00000000..d801b1f7
--- /dev/null
+++ b/pkg/nuget/packagesprops/testdata/variables_and_empty
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file