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

✨ Support Nuget Pinned Dependency with RestoreLockedMode attribute #4351

Merged
merged 23 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1ef8f21
Support restorelockedmode dev (#9)
balteravishay Sep 17, 2024
f1376a8
fixing PR checks and adding tests
balteravishay Sep 18, 2024
a17caa2
move csproj to fileparser
balteravishay Sep 18, 2024
65e8a6e
:seedling: Bump github.com/xanzy/go-gitlab from 0.107.0 to 0.109.0 (#…
dependabot[bot] Sep 16, 2024
f4d8252
internal error
balteravishay Sep 18, 2024
136c2bf
fix using error
balteravishay Sep 18, 2024
2f7ddd7
PR fixes
balteravishay Sep 19, 2024
de3aa58
fix test
balteravishay Sep 19, 2024
3a7de56
:seedling: Bump github.com/onsi/gomega from 1.34.1 to 1.34.2 (#4332)
dependabot[bot] Sep 20, 2024
983e978
:book: explicitly state both check documentation files are committed …
spencerschrock Sep 20, 2024
f87657f
:seedling: Bump cloud.google.com/go/pubsub from 1.42.0 to 1.43.0 (#4350)
dependabot[bot] Sep 25, 2024
ba19c8b
:seedling: Bump github.com/google/osv-scanner from 1.8.4 to 1.8.5 (#4…
dependabot[bot] Sep 25, 2024
379ec5f
:seedling: Bump the distroless group across 6 directories with 1 upda…
dependabot[bot] Sep 25, 2024
ccce3e9
:seedling: Bump the github-actions group across 1 directory with 2 up…
dependabot[bot] Sep 25, 2024
80f126b
:seedling: Bump github.com/rhysd/actionlint from 1.7.1 to 1.7.2 (#4358)
dependabot[bot] Sep 26, 2024
3b709f1
fix pr %e comment
balteravishay Sep 27, 2024
3430457
fix PR comments
balteravishay Sep 29, 2024
32891dc
Co-authored-by: Ioana A <Ioana37@users.noreply.github.com>
balteravishay Sep 29, 2024
4c93325
merge main
balteravishay Oct 1, 2024
d368af1
pr comments
balteravishay Oct 1, 2024
c5ac83f
fix last comments
balteravishay Oct 3, 2024
c43dd68
Merge branch 'main' into support-restorelockedmode
balteravishay Oct 3, 2024
fa2e0bc
Merge branch 'main' into support-restorelockedmode
spencerschrock Oct 3, 2024
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
122 changes: 122 additions & 0 deletions checks/raw/pinned_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ import (
"github.com/ossf/scorecard/v5/checks/fileparser"
sce "github.com/ossf/scorecard/v5/errors"
"github.com/ossf/scorecard/v5/finding"
"github.com/ossf/scorecard/v5/internal/csproj"
"github.com/ossf/scorecard/v5/remediation"
)

type dotnetCsprojLockedData struct {
Path string
LockedModeSet bool
}

// PinningDependencies checks for (un)pinned dependencies.
func PinningDependencies(c *checker.CheckRequest) (checker.PinningDependenciesData, error) {
var results checker.PinningDependenciesData
Expand Down Expand Up @@ -61,9 +67,125 @@ func PinningDependencies(c *checker.CheckRequest) (checker.PinningDependenciesDa
return checker.PinningDependenciesData{}, err
}

if unpinnedNugetDependencies := getUnpinnedNugetDependencies(&results); len(unpinnedNugetDependencies) > 0 {
if err := processCsprojLockedMode(c, unpinnedNugetDependencies); err != nil {
return checker.PinningDependenciesData{}, err
}
}
return results, nil
}

func getUnpinnedNugetDependencies(pinningDependenciesData *checker.PinningDependenciesData) []*checker.Dependency {
var unpinnedNugetDependencies []*checker.Dependency
nugetDependencies := getDependenciesByType(pinningDependenciesData, checker.DependencyUseTypeNugetCommand)
for i := range nugetDependencies {
if !*nugetDependencies[i].Pinned {
unpinnedNugetDependencies = append(unpinnedNugetDependencies, nugetDependencies[i])
}
}
return unpinnedNugetDependencies
}

func getDependenciesByType(p *checker.PinningDependenciesData,
useType checker.DependencyUseType,
) []*checker.Dependency {
var deps []*checker.Dependency
for i := range p.Dependencies {
if p.Dependencies[i].Type == useType {
deps = append(deps, &p.Dependencies[i])
}
}
return deps
}

func processCsprojLockedMode(c *checker.CheckRequest, dependencies []*checker.Dependency) error {
csprojDeps, err := collectCsprojLockedModeData(c)
if err != nil {
return err
}
unlockedCsprojDeps, unlockedPath := countUnlocked(csprojDeps)

// none of the csproject files set RestoreLockedMode. Keep the same status of the nuget dependencies
if unlockedCsprojDeps == len(csprojDeps) {
return nil
}

// all csproj files set RestoreLockedMode, update the dependency pinning status of all nuget dependencies to pinned
if unlockedCsprojDeps == 0 {
pinAllNugetDependencies(dependencies)
} else {
// only some csproj files are locked, keep the same status of the nuget dependencies but create a remediation
for i := range dependencies {
(dependencies)[i].Remediation.Text = (dependencies)[i].Remediation.Text +
": some of your csproj files set the RestoreLockedMode property to true, " +
"while other do not set it: " + unlockedPath
}
}
return nil
}

func pinAllNugetDependencies(dependencies []*checker.Dependency) {
for i := range dependencies {
if dependencies[i].Type == checker.DependencyUseTypeNugetCommand {
dependencies[i].Pinned = asBoolPointer(true)
dependencies[i].Remediation = nil
}
}
}

func collectCsprojLockedModeData(c *checker.CheckRequest) ([]dotnetCsprojLockedData, error) {
var csprojDeps []dotnetCsprojLockedData
if err := fileparser.OnMatchingFileContentDo(c.RepoClient, fileparser.PathMatcher{
Pattern: "*.csproj",
balteravishay marked this conversation as resolved.
Show resolved Hide resolved
CaseSensitive: false,
}, analyseCsprojLockedMode, &csprojDeps, c.Dlogger); err != nil {
return nil, err
}

return csprojDeps, nil
}

func analyseCsprojLockedMode(path string, content []byte, args ...interface{}) (bool, error) {
pdata, ok := args[0].(*[]dotnetCsprojLockedData)
if !ok {
// panic if it is not correct type
panic(fmt.Sprintf("expected type *[]dotnetCsprojLockedData, got %v", reflect.TypeOf(args[0])))
}

pinned, err := csproj.IsRestoreLockedModeEnabled(content)
if err != nil {
dl, ok := args[1].(checker.DetailLogger)
if !ok {
// panic if it is not correct type
panic(fmt.Sprintf("expected type checker.DetailLogger, got %v", reflect.TypeOf(args[1])))
}

dl.Warn(&checker.LogMessage{
Text: fmt.Sprintf("malformed csproj file: %v", err),
})
return true, nil
}

csprojData := dotnetCsprojLockedData{
Path: path,
LockedModeSet: pinned,
}

*pdata = append(*pdata, csprojData)
return true, nil
}

func countUnlocked(csprojFiles []dotnetCsprojLockedData) (int, string) {
var unlockedPaths []string

for i := range csprojFiles {
if !csprojFiles[i].LockedModeSet {
unlockedPaths = append(unlockedPaths, csprojFiles[i].Path)
}
}
return len(unlockedPaths), strings.Join(unlockedPaths, ", ")
}

func dataAsPinnedDependenciesPointer(data interface{}) *checker.PinningDependenciesData {
pdata, ok := data.(*checker.PinningDependenciesData)
if !ok {
Expand Down
Loading
Loading