Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding packages.props and Directory.packages.props parser #268

Merged
merged 28 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8b28c7d
adding packages.props and Directory.packages.props parser
yuriShafet Oct 29, 2023
23ab781
Better error message
yuriShafet Nov 2, 2023
5d4957f
Replacing ElementsMatch with Equal in tests
yuriShafet Nov 2, 2023
48d585d
renaming package folder
yuriShafet Nov 2, 2023
3f7940f
parsePkg function now returns parsed lib
yuriShafet Nov 2, 2023
807c108
removing redundant structs
yuriShafet Nov 2, 2023
2f339bb
refactoring names
yuriShafet Nov 5, 2023
005ea2b
Adding test for severl item groups
yuriShafet Nov 5, 2023
f1fbf12
removing code duplication
yuriShafet Nov 5, 2023
4b877ff
Adding checks for variable package name and version
yuriShafet Nov 5, 2023
d981da7
better names
yuriShafet Nov 10, 2023
d1bfb1e
trimming version and package name
yuriShafet Nov 10, 2023
ede0db3
adding comments
yuriShafet Nov 10, 2023
357b23a
removing var
yuriShafet Nov 10, 2023
138e4c6
removing unnecessary struct
yuriShafet Nov 10, 2023
9d5087b
refactoring: better names
yuriShafet Nov 10, 2023
6733ffb
project element has to be a part of props xml
yuriShafet Nov 10, 2023
7e0925d
more comments
yuriShafet Nov 11, 2023
9d20f1c
refactoring
yuriShafet Nov 11, 2023
4f0a3bd
more refactoring
yuriShafet Nov 11, 2023
d551848
moving comment
yuriShafet Nov 11, 2023
b077453
Merge remote-tracking branch 'refs/remotes/origin/main'
yuriShafet Nov 11, 2023
47f383e
resolving conflict
yuriShafet Nov 11, 2023
c172b93
better naming
yuriShafet Nov 11, 2023
2321d8c
removing unnecessary Trim calls
yuriShafet Nov 11, 2023
5288d1c
Updating comments
yuriShafet Nov 14, 2023
0d91a1d
refactoring libs initialization
yuriShafet Nov 14, 2023
08b9d5c
fixing unit tests
yuriShafet Nov 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions pkg/nuget/packagesprops/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
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
// Based on this documentation both legacy packages.props and Directory.packages.props are supported
// Directory.packages.props example: https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions
yuriShafet marked this conversation as resolved.
Show resolved Hide resolved
type itemGroup struct {
yuriShafet marked this conversation as resolved.
Show resolved Hide resolved
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) {
DmitriyLewen marked this conversation as resolved.
Show resolved Hide resolved
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)
}

libs := make([]types.Library, 0)
DmitriyLewen marked this conversation as resolved.
Show resolved Hide resolved
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
}
82 changes: 82 additions & 0 deletions pkg/nuget/packagesprops/parse_test.go
Original file line number Diff line number Diff line change
@@ -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: "[email protected]"},
{Name: "Microsoft.Extensions.DependencyInjection.Abstractions", Version: "2.2.1", ID: "[email protected]"},
{Name: "Microsoft.Extensions.Http", Version: "3.2.1", ID: "[email protected]"},
},
},
{
name: "DirectoryPackagesProps",
inputFile: "testdata/Directory.Packages.props",
want: []types.Library{
{Name: "PackageOne", Version: "6.2.3", ID: "[email protected]"},
{Name: "PackageTwo", Version: "6.0.0", ID: "[email protected]"},
{Name: "PackageThree", Version: "2.4.1", ID: "[email protected]"},
},
},
{
name: "SeveralItemGroupElements",
inputFile: "testdata/several_item_groups",
want: []types.Library{
{Name: "PackageOne", Version: "6.2.3", ID: "[email protected]"},
{Name: "PackageTwo", Version: "6.0.0", ID: "[email protected]"},
{Name: "PackageThree", Version: "2.4.1", ID: "[email protected]"},
},
},
{
name: "VariablesAsNamesOrVersion",
inputFile: "testdata/variables_and_empty",
want: []types.Library{
{Name: "PackageFour", Version: "2.4.1", ID: "[email protected]"},
},
},
{
name: "NoItemGroupInXMLStructure",
inputFile: "testdata/no_item_group.props",
want: []types.Library{},
},
{
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.ElementsMatch(t, tt.want, got)
DmitriyLewen marked this conversation as resolved.
Show resolved Hide resolved
})
}
}
7 changes: 7 additions & 0 deletions pkg/nuget/packagesprops/testdata/Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project>
<ItemGroup>
<PackageReference Include="PackageOne" Version=" 6.2.3" />
<PackageReference Include="PackageTwo" Version="6.0.0" />
<PackageReference Include="PackageThree " Version="2.4.1" />
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions pkg/nuget/packagesprops/testdata/no_item_group.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PackageReference Update="Microsoft.Extensions.Configuration" Version="2.1.1" />
<PackageReference Update="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.1" />
<PackageReference Update="Microsoft.Extensions.Http" Version="3.2.1" />
<PackageReference WrongAttribute="Package1" Version="3.2.1" />
<WrongEntry Update="Package2" Version="3.2.1" />
<PackageReference Update="Package3" />

</Project>
10 changes: 10 additions & 0 deletions pkg/nuget/packagesprops/testdata/no_project.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>

<ItemGroup Label="Microsoft Nugets">
<PackageReference Update="Microsoft.Extensions.Configuration" Version="2.1.1" />
<PackageReference Update="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.1" />
<PackageReference Update="Microsoft.Extensions.Http" Version="3.2.1" />
<PackageReference WrongAttribute="Package1" Version="3.2.1" />
<WrongEntry Update="Package2" Version="3.2.1" />
<PackageReference Update="Package3" />
</ItemGroup>
11 changes: 11 additions & 0 deletions pkg/nuget/packagesprops/testdata/packages.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="Microsoft Nugets">
<PackageReference Update="Microsoft.Extensions.Configuration" Version="2.1.1" />
<PackageReference Update="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.1" />
<PackageReference Update="Microsoft.Extensions.Http" Version="3.2.1" />
<PackageReference WrongAttribute="Package1" Version="3.2.1" />
<WrongEntry Update="Package2" Version="3.2.1" />
<PackageReference Update="Package3" />
</ItemGroup>
</Project>
10 changes: 10 additions & 0 deletions pkg/nuget/packagesprops/testdata/several_item_groups
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project>
<ItemGroup>
<PackageReference Include="PackageOne" Version="6.2.3" />
<PackageReference Include="PackageTwo" Version="6.0.0" />

</ItemGroup>
<ItemGroup>
<PackageReference Include="PackageThree" Version="2.4.1" />
</ItemGroup>
</Project>
9 changes: 9 additions & 0 deletions pkg/nuget/packagesprops/testdata/variables_and_empty
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>
<ItemGroup>
<PackageReference Include="PackageOne" Version="$(Variable1)" />
<PackageReference Include="$(variable2)" Version="6.0.0" />
<PackageReference Include="" Version="2.4.1" />
<PackageReference Include="package" Version="" />
<PackageReference Include="PackageFour" Version="2.4.1" />
</ItemGroup>
</Project>