mirror of
https://github.com/ossf/scorecard.git
synced 2024-09-11 00:45:36 +03:00
✨ [experimental] Add probe code and support for Tool-Update-Dependency (#2944)
* update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> * update Signed-off-by: laurentsimon <laurentsimon@google.com> --------- Signed-off-by: laurentsimon <laurentsimon@google.com>
This commit is contained in:
parent
f8d33f8b3e
commit
1a336d8087
@ -193,3 +193,26 @@ func CreateRuntimeErrorResult(name string, e error) CheckResult {
|
||||
Reason: e.Error(), // Note: message already accessible by caller thru `Error`.
|
||||
}
|
||||
}
|
||||
|
||||
// LogFindings logs the list of findings.
|
||||
func LogFindings(findings []finding.Finding, dl DetailLogger) error {
|
||||
for i := range findings {
|
||||
f := &findings[i]
|
||||
switch f.Outcome {
|
||||
case finding.OutcomeNegative:
|
||||
dl.Warn(&LogMessage{
|
||||
Finding: f,
|
||||
})
|
||||
case finding.OutcomePositive:
|
||||
dl.Info(&LogMessage{
|
||||
Finding: f,
|
||||
})
|
||||
default:
|
||||
dl.Debug(&LogMessage{
|
||||
Finding: f,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -242,7 +242,6 @@ type SignedReleasesData struct {
|
||||
// for the Dependency-Update-Tool check.
|
||||
type DependencyUpdateToolData struct {
|
||||
// Tools contains a list of tools.
|
||||
// Note: we only populate one entry at most.
|
||||
Tools []Tool
|
||||
}
|
||||
|
||||
@ -375,3 +374,24 @@ type TokenPermission struct {
|
||||
Msg *string
|
||||
Type PermissionLevel
|
||||
}
|
||||
|
||||
// Location generates location from a file.
|
||||
func (f *File) Location() *finding.Location {
|
||||
// TODO(2626): merge location and path.
|
||||
if f == nil {
|
||||
return nil
|
||||
}
|
||||
loc := &finding.Location{
|
||||
Type: f.Type,
|
||||
Path: f.Path,
|
||||
LineStart: &f.Offset,
|
||||
}
|
||||
if f.EndOffset != 0 {
|
||||
loc.LineEnd = &f.EndOffset
|
||||
}
|
||||
if f.Snippet != "" {
|
||||
loc.Snippet = &f.Snippet
|
||||
}
|
||||
|
||||
return loc
|
||||
}
|
||||
|
@ -19,12 +19,13 @@ import (
|
||||
"github.com/ossf/scorecard/v4/checks/evaluation"
|
||||
"github.com/ossf/scorecard/v4/checks/raw"
|
||||
sce "github.com/ossf/scorecard/v4/errors"
|
||||
"github.com/ossf/scorecard/v4/probes"
|
||||
)
|
||||
|
||||
// CheckDependencyUpdateTool is the exported name for Automatic-Depdendency-Update.
|
||||
const CheckDependencyUpdateTool = "Dependency-Update-Tool"
|
||||
|
||||
//nolint
|
||||
// nolint
|
||||
func init() {
|
||||
supportedRequestTypes := []checker.RequestType{
|
||||
checker.FileBased,
|
||||
@ -48,6 +49,13 @@ func DependencyUpdateTool(c *checker.CheckRequest) checker.CheckResult {
|
||||
c.RawResults.DependencyUpdateToolResults = rawData
|
||||
}
|
||||
|
||||
// Evaluate the probes.
|
||||
findings, err := evaluateProbes(c, CheckDependencyUpdateTool, probes.DependencyToolUpdates)
|
||||
if err != nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
||||
return checker.CreateRuntimeErrorResult(CheckDependencyUpdateTool, e)
|
||||
}
|
||||
|
||||
// Return the score evaluation.
|
||||
return evaluation.DependencyUpdateTool(CheckDependencyUpdateTool, c.Dlogger, &rawData)
|
||||
return evaluation.DependencyUpdateTool(CheckDependencyUpdateTool, findings)
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
CallSearchCommits: 0,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfInfo: 1,
|
||||
NumberOfWarn: 3,
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
@ -63,6 +64,7 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
CallSearchCommits: 0,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfInfo: 1,
|
||||
NumberOfWarn: 3,
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
@ -75,7 +77,7 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
SearchCommits: []clients.Commit{{Committer: clients.User{ID: 111111111}}},
|
||||
CallSearchCommits: 1,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfWarn: 1,
|
||||
NumberOfWarn: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -87,7 +89,7 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
SearchCommits: []clients.Commit{},
|
||||
CallSearchCommits: 1,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfWarn: 1,
|
||||
NumberOfWarn: 4,
|
||||
},
|
||||
},
|
||||
|
||||
@ -101,6 +103,7 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
CallSearchCommits: 1,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfInfo: 1,
|
||||
NumberOfWarn: 3,
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
@ -108,13 +111,14 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
name: "found in commits 2",
|
||||
wantErr: false,
|
||||
files: []string{},
|
||||
SearchCommits: []clients.Commit{{Committer: clients.User{ID: 111111111}},
|
||||
SearchCommits: []clients.Commit{
|
||||
{Committer: clients.User{ID: 111111111}},
|
||||
{Committer: clients.User{ID: dependabotID}},
|
||||
},
|
||||
|
||||
CallSearchCommits: 1,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfInfo: 1,
|
||||
NumberOfWarn: 3,
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
@ -125,12 +129,14 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
files: []string{
|
||||
".github/foobar.yml",
|
||||
},
|
||||
SearchCommits: []clients.Commit{{Committer: clients.User{ID: 111111111}},
|
||||
SearchCommits: []clients.Commit{
|
||||
{Committer: clients.User{ID: 111111111}},
|
||||
{Committer: clients.User{ID: dependabotID}},
|
||||
},
|
||||
CallSearchCommits: 1,
|
||||
expected: scut.TestReturn{
|
||||
NumberOfInfo: 1,
|
||||
NumberOfWarn: 3,
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
@ -144,9 +150,11 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
mockRepo.EXPECT().ListFiles(gomock.Any()).Return(tt.files, nil)
|
||||
mockRepo.EXPECT().SearchCommits(gomock.Any()).Return(tt.SearchCommits, nil).Times(tt.CallSearchCommits)
|
||||
dl := scut.TestDetailLogger{}
|
||||
raw := checker.RawResults{}
|
||||
c := &checker.CheckRequest{
|
||||
RepoClient: mockRepo,
|
||||
Dlogger: &dl,
|
||||
RawResults: &raw,
|
||||
}
|
||||
res := DependencyUpdateTool(c)
|
||||
|
||||
|
@ -15,51 +15,20 @@
|
||||
package evaluation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
sce "github.com/ossf/scorecard/v4/errors"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
)
|
||||
|
||||
// DependencyUpdateTool applies the score policy for the Dependency-Update-Tool check.
|
||||
func DependencyUpdateTool(name string, dl checker.DetailLogger,
|
||||
r *checker.DependencyUpdateToolData,
|
||||
func DependencyUpdateTool(name string,
|
||||
findings []finding.Finding,
|
||||
) checker.CheckResult {
|
||||
if r == nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data")
|
||||
return checker.CreateRuntimeErrorResult(name, e)
|
||||
for i := range findings {
|
||||
f := &findings[i]
|
||||
if f.Outcome == finding.OutcomePositive {
|
||||
return checker.CreateMaxScoreResult(name, "update tool detected")
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the policy evaluation.
|
||||
if r.Tools == nil || len(r.Tools) == 0 {
|
||||
dl.Warn(&checker.LogMessage{
|
||||
Text: `Config file not detected in source location for dependabot, renovatebot, Sonatype Lift, or
|
||||
PyUp (Python). We recommend setting this configuration in code so it can be easily verified by others.`,
|
||||
})
|
||||
return checker.CreateMinScoreResult(name, "no update tool detected")
|
||||
}
|
||||
|
||||
// Validate the input.
|
||||
if len(r.Tools) != 1 {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("found %d tools, expected 1", len(r.Tools)))
|
||||
return checker.CreateRuntimeErrorResult(name, e)
|
||||
}
|
||||
|
||||
if r.Tools[0].Files == nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, "Files are nil")
|
||||
return checker.CreateRuntimeErrorResult(name, e)
|
||||
}
|
||||
|
||||
// Iterate over all the files, since a Tool can contain multiple files.
|
||||
for _, file := range r.Tools[0].Files {
|
||||
dl.Info(&checker.LogMessage{
|
||||
Path: file.Path,
|
||||
Type: file.Type,
|
||||
Offset: file.Offset,
|
||||
Text: fmt.Sprintf("%s detected", r.Tools[0].Name),
|
||||
})
|
||||
}
|
||||
|
||||
// High score result.
|
||||
return checker.CreateMaxScoreResult(name, "update tool detected")
|
||||
return checker.CreateMinScoreResult(name, "no update tool detected")
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
sce "github.com/ossf/scorecard/v4/errors"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
scut "github.com/ossf/scorecard/v4/utests"
|
||||
)
|
||||
@ -26,135 +25,91 @@ import (
|
||||
func TestDependencyUpdateTool(t *testing.T) {
|
||||
t.Parallel()
|
||||
//nolint
|
||||
type args struct {
|
||||
name string
|
||||
dl checker.DetailLogger
|
||||
r *checker.DependencyUpdateToolData
|
||||
}
|
||||
//nolint
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want checker.CheckResult
|
||||
findings []finding.Finding
|
||||
err bool
|
||||
want checker.CheckResult
|
||||
expected scut.TestReturn
|
||||
}{
|
||||
{
|
||||
name: "DependencyUpdateTool",
|
||||
args: args{
|
||||
name: "DependencyUpdateTool",
|
||||
dl: &scut.TestDetailLogger{},
|
||||
r: &checker.DependencyUpdateToolData{
|
||||
Tools: []checker.Tool{
|
||||
{
|
||||
Name: "DependencyUpdateTool",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: -1,
|
||||
},
|
||||
err: false,
|
||||
expected: scut.TestReturn{
|
||||
Error: sce.ErrScorecardInternal,
|
||||
Score: -1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty tool list",
|
||||
args: args{
|
||||
name: "DependencyUpdateTool",
|
||||
dl: &scut.TestDetailLogger{},
|
||||
r: &checker.DependencyUpdateToolData{
|
||||
Tools: []checker.Tool{},
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: 0,
|
||||
Error: nil,
|
||||
},
|
||||
err: false,
|
||||
expected: scut.TestReturn{
|
||||
Score: 0,
|
||||
NumberOfWarn: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid tool",
|
||||
args: args{
|
||||
name: "DependencyUpdateTool",
|
||||
dl: &scut.TestDetailLogger{},
|
||||
r: &checker.DependencyUpdateToolData{
|
||||
Tools: []checker.Tool{
|
||||
{
|
||||
Name: "DependencyUpdateTool",
|
||||
Files: []checker.File{
|
||||
{
|
||||
Path: "/etc/dependency-update-tool.conf",
|
||||
Snippet: `
|
||||
[dependency-update-tool]
|
||||
enabled = true
|
||||
`,
|
||||
Type: finding.FileTypeSource,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
name: "dependabot",
|
||||
findings: []finding.Finding{
|
||||
{
|
||||
Probe: "toolDependabotInstalled",
|
||||
Outcome: finding.OutcomePositive,
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: 10,
|
||||
Error: nil,
|
||||
},
|
||||
expected: scut.TestReturn{
|
||||
Error: nil,
|
||||
Score: 10,
|
||||
NumberOfInfo: 1,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "more than one tool in the list",
|
||||
args: args{
|
||||
name: "DependencyUpdateTool",
|
||||
dl: &scut.TestDetailLogger{},
|
||||
r: &checker.DependencyUpdateToolData{
|
||||
Tools: []checker.Tool{
|
||||
{
|
||||
Name: "DependencyUpdateTool",
|
||||
},
|
||||
{
|
||||
Name: "DependencyUpdateTool",
|
||||
},
|
||||
},
|
||||
name: "renovate",
|
||||
findings: []finding.Finding{
|
||||
{
|
||||
Probe: "toolRenovateInstalled",
|
||||
Outcome: finding.OutcomePositive,
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: -1,
|
||||
Error: nil,
|
||||
Score: 10,
|
||||
},
|
||||
expected: scut.TestReturn{
|
||||
Error: sce.ErrScorecardInternal,
|
||||
Score: -1,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "Nil r",
|
||||
args: args{
|
||||
name: "nil r",
|
||||
dl: &scut.TestDetailLogger{},
|
||||
name: "pyup",
|
||||
findings: []finding.Finding{
|
||||
{
|
||||
Probe: "toolPyUpInstalled",
|
||||
Outcome: finding.OutcomePositive,
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: -1,
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sonatype",
|
||||
findings: []finding.Finding{
|
||||
{
|
||||
Probe: "toolSonatypeInstalled",
|
||||
Outcome: finding.OutcomePositive,
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "none",
|
||||
findings: []finding.Finding{
|
||||
{
|
||||
Probe: "toolDependabotInstalled",
|
||||
Outcome: finding.OutcomeNegative,
|
||||
},
|
||||
{
|
||||
Probe: "toolRenovateInstalled",
|
||||
Outcome: finding.OutcomeNegative,
|
||||
},
|
||||
{
|
||||
Probe: "toolPyUpInstalled",
|
||||
Outcome: finding.OutcomeNegative,
|
||||
},
|
||||
{
|
||||
Probe: "toolSonatypeInstalled",
|
||||
Outcome: finding.OutcomeNegative,
|
||||
},
|
||||
},
|
||||
want: checker.CheckResult{
|
||||
Score: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty tool list",
|
||||
want: checker.CheckResult{
|
||||
Score: 0,
|
||||
Error: nil,
|
||||
},
|
||||
expected: scut.TestReturn{
|
||||
Error: sce.ErrScorecardInternal,
|
||||
Score: -1,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -162,8 +117,7 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dl := scut.TestDetailLogger{}
|
||||
got := DependencyUpdateTool(tt.args.name, &dl, tt.args.r)
|
||||
got := DependencyUpdateTool(tt.name, tt.findings)
|
||||
if tt.want.Score != got.Score {
|
||||
t.Errorf("DependencyUpdateTool() got Score = %v, want %v for %v", got.Score, tt.want.Score, tt.name)
|
||||
}
|
||||
@ -171,10 +125,6 @@ func TestDependencyUpdateTool(t *testing.T) {
|
||||
t.Errorf("DependencyUpdateTool() error = %v, want %v for %v", got.Error, tt.want.Error, tt.name)
|
||||
return
|
||||
}
|
||||
|
||||
if !scut.ValidateTestReturn(t, tt.name, &tt.expected, &got, &dl) {
|
||||
t.Fatalf(tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -126,13 +126,11 @@ var checkDependencyFileExists fileparser.DoWhileTrueOnFilename = func(name strin
|
||||
},
|
||||
},
|
||||
})
|
||||
default:
|
||||
// Continue iterating.
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// We found a file, no need to continue iterating.
|
||||
return false, nil
|
||||
// Continue iterating, even if we have found a tool.
|
||||
// It's needed for all probes results to be populated.
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func asPointer(s string) *string {
|
||||
|
@ -26,115 +26,84 @@ import (
|
||||
|
||||
func Test_checkDependencyFileExists(t *testing.T) {
|
||||
t.Parallel()
|
||||
//nolint
|
||||
type args struct {
|
||||
name string
|
||||
data *[]checker.Tool
|
||||
}
|
||||
|
||||
//nolint
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
path string
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "check dependency file exists",
|
||||
args: args{
|
||||
name: ".github/dependabot.yml",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".other",
|
||||
args: args{
|
||||
name: ".other",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
name: ".github/dependabot.yml",
|
||||
path: ".github/dependabot.yml",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".github/renovate.json",
|
||||
args: args{
|
||||
name: ".github/renovate.json",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
name: ".github/dependabot.yaml",
|
||||
path: ".github/dependabot.yaml",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".other",
|
||||
path: ".other",
|
||||
want: false,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".github/renovate.json5",
|
||||
args: args{
|
||||
name: ".github/renovate.json5",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: ".github/renovate.json",
|
||||
path: ".github/renovate.json",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".renovaterc.json",
|
||||
args: args{
|
||||
name: ".renovaterc.json",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: ".github/renovate.json5",
|
||||
path: ".github/renovate.json5",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "renovate.json",
|
||||
args: args{
|
||||
name: "renovate.json",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: ".renovaterc.json",
|
||||
path: ".renovaterc.json",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "renovate.json5",
|
||||
args: args{
|
||||
name: "renovate.json5",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: "renovate.json",
|
||||
path: "renovate.json",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".renovaterc",
|
||||
args: args{
|
||||
name: ".renovaterc",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: "renovate.json5",
|
||||
path: "renovate.json5",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".pyup.yml",
|
||||
args: args{
|
||||
name: ".pyup.yml",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: ".renovaterc",
|
||||
path: ".renovaterc",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".lift.toml",
|
||||
args: args{
|
||||
name: ".lift.toml",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: ".pyup.yml",
|
||||
path: ".pyup.yml",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".lift/config.toml",
|
||||
args: args{
|
||||
name: ".lift/config.toml",
|
||||
data: &[]checker.Tool{},
|
||||
},
|
||||
want: false,
|
||||
name: ".lift.toml",
|
||||
path: ".lift.toml",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: ".lift/config.toml",
|
||||
path: ".lift/config.toml",
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
@ -142,13 +111,17 @@ func Test_checkDependencyFileExists(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := checkDependencyFileExists(tt.args.name, tt.args.data)
|
||||
results := []checker.Tool{}
|
||||
cont, err := checkDependencyFileExists(tt.path, &results)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("checkDependencyFileExists() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("checkDependencyFileExists() = %v, want %v for test %v", got, tt.want, tt.name)
|
||||
if !cont {
|
||||
t.Errorf("continue is false for %v", tt.name)
|
||||
}
|
||||
if tt.want != (len(results) == 1) {
|
||||
t.Errorf("checkDependencyFileExists() = %v, want %v for test %v", len(results), tt.want, tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
41
checks/run_probes.go
Normal file
41
checks/run_probes.go
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2023 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package checks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes"
|
||||
"github.com/ossf/scorecard/v4/probes/zrunner"
|
||||
)
|
||||
|
||||
// evaluateProbes runs the probes in probesToRun and logs its findings.
|
||||
func evaluateProbes(c *checker.CheckRequest, checkName string,
|
||||
probesToRun []probes.ProbeImpl,
|
||||
) ([]finding.Finding, error) {
|
||||
// Run the probes.
|
||||
findings, err := zrunner.Run(c.RawResults, probesToRun)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("zrunner.Run: %w", err)
|
||||
}
|
||||
|
||||
// Log the findings.
|
||||
if err := checker.LogFindings(findings, c.Dlogger); err != nil {
|
||||
return nil, fmt.Errorf("LogFindings: %w", err)
|
||||
}
|
||||
return findings, nil
|
||||
}
|
@ -39,16 +39,18 @@ var _ = Describe("E2E TEST:"+checks.CheckDependencyUpdateTool, func() {
|
||||
err = repoClient.InitRepo(repo, clients.HeadSHA, 0)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
raw := checker.RawResults{}
|
||||
req := checker.CheckRequest{
|
||||
Ctx: context.Background(),
|
||||
RepoClient: repoClient,
|
||||
Repo: repo,
|
||||
Dlogger: &dl,
|
||||
RawResults: &raw,
|
||||
}
|
||||
expected := scut.TestReturn{
|
||||
Error: nil,
|
||||
Score: checker.MaxResultScore,
|
||||
NumberOfWarn: 0,
|
||||
NumberOfWarn: 3,
|
||||
NumberOfInfo: 1,
|
||||
NumberOfDebug: 0,
|
||||
}
|
||||
@ -66,16 +68,18 @@ var _ = Describe("E2E TEST:"+checks.CheckDependencyUpdateTool, func() {
|
||||
err = repoClient.InitRepo(repo, clients.HeadSHA, 0)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
raw := checker.RawResults{}
|
||||
req := checker.CheckRequest{
|
||||
Ctx: context.Background(),
|
||||
RepoClient: repoClient,
|
||||
Repo: repo,
|
||||
Dlogger: &dl,
|
||||
RawResults: &raw,
|
||||
}
|
||||
expected := scut.TestReturn{
|
||||
Error: nil,
|
||||
Score: checker.MaxResultScore,
|
||||
NumberOfWarn: 0,
|
||||
NumberOfWarn: 3,
|
||||
NumberOfInfo: 1,
|
||||
NumberOfDebug: 0,
|
||||
}
|
||||
|
59
probes/entries.go
Normal file
59
probes/entries.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2023 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package probes
|
||||
|
||||
import (
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes/toolDependabotInstalled"
|
||||
"github.com/ossf/scorecard/v4/probes/toolPyUpInstalled"
|
||||
"github.com/ossf/scorecard/v4/probes/toolRenovateInstalled"
|
||||
"github.com/ossf/scorecard/v4/probes/toolSonatypeLiftInstalled"
|
||||
)
|
||||
|
||||
// ProbeImpl is the implementation of a probe.
|
||||
type ProbeImpl func(*checker.RawResults) ([]finding.Finding, string, error)
|
||||
|
||||
var (
|
||||
// All represents all the probes.
|
||||
All []ProbeImpl
|
||||
// DependencyToolUpdates is all the probes for the
|
||||
// DpendencyUpdateTool check.
|
||||
DependencyToolUpdates = []ProbeImpl{
|
||||
toolRenovateInstalled.Run,
|
||||
toolDependabotInstalled.Run,
|
||||
toolPyUpInstalled.Run,
|
||||
toolSonatypeLiftInstalled.Run,
|
||||
}
|
||||
)
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
All = concatMultipleProbes([][]ProbeImpl{
|
||||
DependencyToolUpdates,
|
||||
})
|
||||
}
|
||||
|
||||
func concatMultipleProbes(slices [][]ProbeImpl) []ProbeImpl {
|
||||
var totalLen int
|
||||
for _, s := range slices {
|
||||
totalLen += len(s)
|
||||
}
|
||||
tmp := make([]ProbeImpl, 0, totalLen)
|
||||
for _, s := range slices {
|
||||
tmp = append(tmp, s...)
|
||||
}
|
||||
return tmp
|
||||
}
|
32
probes/toolDependabotInstalled/def.yml
Normal file
32
probes/toolDependabotInstalled/def.yml
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2023 OpenSSF Scorecard Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
id: toolDependabotInstalled
|
||||
short: Check that Dependabot is enabled
|
||||
motivation: >
|
||||
Out-of-date dependencies make a project vulnerable to known flaws and prone to attacks.
|
||||
Dependabot automates the process of updating dependencies by scanning for outdated or insecure requirements, and opening a pull request to update them if found.
|
||||
implementation: >
|
||||
The implemtation looks for the presence of files named ".github/dependabot.yml" or ".github/dependabot.yaml". If none of these files are found,
|
||||
the implementation checks whether commits are authored by Dependabot. If none of these succeed, Dependabot is not installed.
|
||||
NOTE: if the configuration files are found, the probe does not ensure that the Dependabot is run or that the Dependabot's pull requests are merged.
|
||||
outcome:
|
||||
- If dependendabot is installed, the probe returns OutcomePositive (1)
|
||||
- If dependendabot is not installed, the probe returns OutcomeNegative (0)
|
||||
remediation:
|
||||
effort: Low
|
||||
text:
|
||||
- Follow the instructions from https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates.
|
||||
markdown:
|
||||
- Follow the instructions from [the official documentation](https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates).
|
53
probes/toolDependabotInstalled/impl.go
Normal file
53
probes/toolDependabotInstalled/impl.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2022 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// nolint:stylecheck
|
||||
package toolDependabotInstalled
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes/utils"
|
||||
)
|
||||
|
||||
//go:embed *.yml
|
||||
var fs embed.FS
|
||||
|
||||
const probe = "toolDependabotInstalled"
|
||||
|
||||
type dependabot struct{}
|
||||
|
||||
func (t dependabot) Name() string {
|
||||
return "Dependabot"
|
||||
}
|
||||
|
||||
func (t dependabot) Matches(tool *checker.Tool) bool {
|
||||
return t.Name() == tool.Name
|
||||
}
|
||||
|
||||
func Run(raw *checker.RawResults) ([]finding.Finding, string, error) {
|
||||
tools := raw.DependencyUpdateToolResults.Tools
|
||||
var matcher dependabot
|
||||
// Check whether Dependabot tool is installed on the repo,
|
||||
// and create the corresponding findings.
|
||||
//nolint:wrapcheck
|
||||
return utils.ToolsRun(tools, fs, probe,
|
||||
// Tool found will generate a positive result.
|
||||
finding.OutcomePositive,
|
||||
// Tool not found will generate a negative result.
|
||||
finding.OutcomeNegative,
|
||||
matcher)
|
||||
}
|
32
probes/toolPyUpInstalled/def.yml
Normal file
32
probes/toolPyUpInstalled/def.yml
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2023 OpenSSF Scorecard Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
id: toolPyUpInstalled
|
||||
short: Check that PyUp is installed.
|
||||
motivation: >
|
||||
Out-of-date dependencies make a project vulnerable to known flaws and prone to attacks.
|
||||
PyUp automates the process of updating dependencies by scanning for outdated or insecure requirements, and opening a pull request to update them if found.
|
||||
implementation: >
|
||||
The implementation looks for the presence of a file named ".pyup.yml".
|
||||
If the file is not found, PyUp is not installed.
|
||||
NOTE: the implementation does not ensure that PyUp is run or that PyUp's pull requests are merged.
|
||||
outcome:
|
||||
- If PyUp is installed, the probe returns OutcomePositive (1)
|
||||
- If PyUp is not installed, the probe returns OutcomeNegative (0)
|
||||
remediation:
|
||||
effort: Low
|
||||
text:
|
||||
- Follow the instructions from https://docs.pyup.io/docs.
|
||||
markdown:
|
||||
- Follow the instructions from [the official documentation](https://docs.pyup.io/docs).
|
53
probes/toolPyUpInstalled/impl.go
Normal file
53
probes/toolPyUpInstalled/impl.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2022 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// nolint:stylecheck
|
||||
package toolPyUpInstalled
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes/utils"
|
||||
)
|
||||
|
||||
//go:embed *.yml
|
||||
var fs embed.FS
|
||||
|
||||
const probe = "toolPyUpInstalled"
|
||||
|
||||
type pyup struct{}
|
||||
|
||||
func (t pyup) Name() string {
|
||||
return "PyUp"
|
||||
}
|
||||
|
||||
func (t pyup) Matches(tool *checker.Tool) bool {
|
||||
return t.Name() == tool.Name
|
||||
}
|
||||
|
||||
func Run(raw *checker.RawResults) ([]finding.Finding, string, error) {
|
||||
tools := raw.DependencyUpdateToolResults.Tools
|
||||
var matcher pyup
|
||||
// Check whether PyUp tool is installed on the repo,
|
||||
// and create the corresponding findings.
|
||||
//nolint:wrapcheck
|
||||
return utils.ToolsRun(tools, fs, probe,
|
||||
// Tool found will generate a positive result.
|
||||
finding.OutcomePositive,
|
||||
// Tool not found will generate a negative result.
|
||||
finding.OutcomeNegative,
|
||||
matcher)
|
||||
}
|
32
probes/toolRenovateInstalled/def.yml
Normal file
32
probes/toolRenovateInstalled/def.yml
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2023 OpenSSF Scorecard Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
id: toolRenovateInstalled
|
||||
short: Check that Renovate bot is installed.
|
||||
motivation: >
|
||||
Out-of-date dependencies make a project vulnerable to known flaws and prone to attacks.
|
||||
Renovate automates the process of updating dependencies by scanning for outdated or insecure requirements, and opening a pull request to update them if found.
|
||||
implementation: >
|
||||
The implementation looks for the presence of files named ".github/renovate.json", ".github/renovate.json5", ".renovaterc.json" or. "renovate.json".
|
||||
If none of these files are found, Renovate is not installed.
|
||||
NOTE: the implementation does not ensure that Renovate is run or that Renovate's pull requests are merged.
|
||||
outcome:
|
||||
- If Renovate is installed, the probe returns OutcomePositive (1)
|
||||
- If Renovate is not installed, the probe returns OutcomeNegative (0)
|
||||
remediation:
|
||||
effort: Low
|
||||
text:
|
||||
- Follow the instructions from https://docs.renovatebot.com/configuration-options/.
|
||||
markdown:
|
||||
- Follow the instructions from [the official documentation](https://docs.renovatebot.com/configuration-options/).
|
53
probes/toolRenovateInstalled/impl.go
Normal file
53
probes/toolRenovateInstalled/impl.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2022 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// nolint:stylecheck
|
||||
package toolRenovateInstalled
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes/utils"
|
||||
)
|
||||
|
||||
//go:embed *.yml
|
||||
var fs embed.FS
|
||||
|
||||
const probe = "toolRenovateInstalled"
|
||||
|
||||
type renovate struct{}
|
||||
|
||||
func (t renovate) Name() string {
|
||||
return "RenovateBot"
|
||||
}
|
||||
|
||||
func (t renovate) Matches(tool *checker.Tool) bool {
|
||||
return t.Name() == tool.Name
|
||||
}
|
||||
|
||||
func Run(raw *checker.RawResults) ([]finding.Finding, string, error) {
|
||||
tools := raw.DependencyUpdateToolResults.Tools
|
||||
var matcher renovate
|
||||
// Check whether Renovate tool is installed on the repo,
|
||||
// and create the corresponding findings.
|
||||
//nolint:wrapcheck
|
||||
return utils.ToolsRun(tools, fs, probe,
|
||||
// Tool found will generate a positive result.
|
||||
finding.OutcomePositive,
|
||||
// Tool not found will generate a negative result.
|
||||
finding.OutcomeNegative,
|
||||
matcher)
|
||||
}
|
32
probes/toolSonatypeLiftInstalled/def.yml
Normal file
32
probes/toolSonatypeLiftInstalled/def.yml
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2023 OpenSSF Scorecard Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
id: toolSonatypeLiftInstalled
|
||||
short: Check that Sonatype Lyft is installed.
|
||||
motivation: >
|
||||
Out-of-date dependencies make a project vulnerable to known flaws and prone to attacks.
|
||||
Sonatype Lyft automates the process of updating dependencies by scanning for outdated or insecure requirements, and opening a pull request to update them if found.
|
||||
implementation: >
|
||||
The implementation looks for the presence of files named ".lift.toml" or ".lift/config.toml".
|
||||
If none of these files are found, Sonatype Lyft is not installed.
|
||||
NOTE: the implementation does not ensure that Sonatype Lyft is run or that Sonatype Lyft's pull requests are merged.
|
||||
outcome:
|
||||
- If Sonatype Lyft is installed, the probe returns OutcomePositive (1)
|
||||
- If Sonatype Lyft is not installed, the probe returns OutcomeNegative (0)
|
||||
remediation:
|
||||
effort: Low
|
||||
text:
|
||||
- Follow the instructions from https://help.sonatype.com/lift/getting-started.
|
||||
markdown:
|
||||
- Follow the instructions from [the official documentation](https://help.sonatype.com/lift/getting-started).
|
53
probes/toolSonatypeLiftInstalled/impl.go
Normal file
53
probes/toolSonatypeLiftInstalled/impl.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2022 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// nolint:stylecheck
|
||||
package toolSonatypeLiftInstalled
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes/utils"
|
||||
)
|
||||
|
||||
//go:embed *.yml
|
||||
var fs embed.FS
|
||||
|
||||
const probe = "toolSonatypeLiftInstalled"
|
||||
|
||||
type sonatypeLyft struct{}
|
||||
|
||||
func (t sonatypeLyft) Name() string {
|
||||
return "Sonatype Lift"
|
||||
}
|
||||
|
||||
func (t sonatypeLyft) Matches(tool *checker.Tool) bool {
|
||||
return t.Name() == tool.Name
|
||||
}
|
||||
|
||||
func Run(raw *checker.RawResults) ([]finding.Finding, string, error) {
|
||||
tools := raw.DependencyUpdateToolResults.Tools
|
||||
var matcher sonatypeLyft
|
||||
// Check whether Sona Lyft tool is installed on the repo,
|
||||
// and create the corresponding findings.
|
||||
//nolint:wrapcheck
|
||||
return utils.ToolsRun(tools, fs, probe,
|
||||
// Tool found will generate a positive result.
|
||||
finding.OutcomePositive,
|
||||
// Tool not found will generate a negative result.
|
||||
finding.OutcomeNegative,
|
||||
matcher)
|
||||
}
|
69
probes/utils/tools.go
Normal file
69
probes/utils/tools.go
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2023 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
)
|
||||
|
||||
type toolMatcher interface {
|
||||
Name() string
|
||||
Matches(*checker.Tool) bool
|
||||
}
|
||||
|
||||
// ToolsRun runs the probe for a tool.
|
||||
// The function iterates thru the raw results and searches for a tool of interest that is used on a repository.
|
||||
// The function uses 'matcher' to identify the tool of interest.
|
||||
// If a tool is used in the repository, it creates a finding with the 'foundOutcome'.
|
||||
// If not, it returns a finding with outcome 'notFoundOutcome'.
|
||||
func ToolsRun(tools []checker.Tool, fs embed.FS, probeID string,
|
||||
foundOutcome, notFoundOutcome finding.Outcome, matcher toolMatcher,
|
||||
) ([]finding.Finding, string, error) {
|
||||
var findings []finding.Finding
|
||||
for i := range tools {
|
||||
tool := &tools[i]
|
||||
if !matcher.Matches(tool) {
|
||||
continue
|
||||
}
|
||||
|
||||
var loc *finding.Location
|
||||
if len(tool.Files) > 0 {
|
||||
loc = tool.Files[0].Location()
|
||||
}
|
||||
|
||||
f, err := finding.NewWith(fs, probeID, fmt.Sprintf("tool '%s' is used", tool.Name),
|
||||
loc, foundOutcome)
|
||||
if err != nil {
|
||||
return nil, probeID, fmt.Errorf("create finding: %w", err)
|
||||
}
|
||||
findings = append(findings, *f)
|
||||
}
|
||||
|
||||
// No tools found.
|
||||
if len(findings) == 0 {
|
||||
f, err := finding.NewWith(fs, probeID, fmt.Sprintf("tool '%s' is not used", matcher.Name()),
|
||||
nil, notFoundOutcome)
|
||||
if err != nil {
|
||||
return nil, probeID, fmt.Errorf("create finding: %w", err)
|
||||
}
|
||||
findings = append(findings, *f)
|
||||
}
|
||||
|
||||
return findings, probeID, nil
|
||||
}
|
51
probes/zrunner/runner.go
Normal file
51
probes/zrunner/runner.go
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2023 OpenSSF Scorecard Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package zrunner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ossf/scorecard/v4/checker"
|
||||
serrors "github.com/ossf/scorecard/v4/errors"
|
||||
"github.com/ossf/scorecard/v4/finding"
|
||||
"github.com/ossf/scorecard/v4/probes"
|
||||
)
|
||||
|
||||
var errProbeRun = errors.New("probe run failure")
|
||||
|
||||
// Run runs the probes in probesToRun.
|
||||
func Run(raw *checker.RawResults, probesToRun []probes.ProbeImpl) ([]finding.Finding, error) {
|
||||
var results []finding.Finding
|
||||
var errs []error
|
||||
for _, probeFunc := range probesToRun {
|
||||
findings, probeID, err := probeFunc(raw)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
results = append(results,
|
||||
finding.Finding{
|
||||
Probe: probeID,
|
||||
Outcome: finding.OutcomeError,
|
||||
Message: serrors.WithMessage(serrors.ErrScorecardInternal, err.Error()).Error(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
results = append(results, findings...)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return results, fmt.Errorf("%w: %v", errProbeRun, errs)
|
||||
}
|
||||
return results, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user