Skip to content

Commit

Permalink
🌱 Convert pinned dependencies to probe (ossf#3829)
Browse files Browse the repository at this point in the history
* 🌱 Convert pinned dependencies to probe

Signed-off-by: Adam Korczynski <[email protected]>

* add more tests

Signed-off-by: Adam Korczynski <[email protected]>

* add checks unit test

Signed-off-by: Adam Korczynski <[email protected]>

* fix year in probe header and add mising test file

Signed-off-by: Adam Korczynski <[email protected]>

* Change usage of ValidateTestReturn

Signed-off-by: Adam Korczynski <[email protected]>

* rename test

Signed-off-by: Adam Korczynski <[email protected]>

* change 'pinned' to 'unpinned' in test name

Signed-off-by: Adam Korczynski <[email protected]>

* export 'depTypeKey'

Signed-off-by: Adam Korczynski <[email protected]>

* Do not copy test Dockerfile

Signed-off-by: Adam Korczynski <[email protected]>

* rename test

Signed-off-by: Adam Korczynski <[email protected]>

* Rebase and bring back 'Test_generateOwnerToDisplay'

Signed-off-by: Adam Korczynski <[email protected]>

* Use API to create finding

Signed-off-by: AdamKorcz <[email protected]>

* one more change to how the probe creates a finding

Signed-off-by: AdamKorcz <[email protected]>

---------

Signed-off-by: Adam Korczynski <[email protected]>
Signed-off-by: AdamKorcz <[email protected]>
  • Loading branch information
AdamKorcz authored and fhoeborn committed Apr 1, 2024
1 parent 1c0fe27 commit 0cbcacb
Show file tree
Hide file tree
Showing 8 changed files with 1,134 additions and 762 deletions.
154 changes: 14 additions & 140 deletions checks/evaluation/pinned_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
sce "github.com/ossf/scorecard/v4/errors"
"github.com/ossf/scorecard/v4/finding"
"github.com/ossf/scorecard/v4/finding/probe"
"github.com/ossf/scorecard/v4/probes/pinsDependencies"
"github.com/ossf/scorecard/v4/rule"
)

Expand Down Expand Up @@ -49,20 +50,8 @@ const (
gitHubOwnedActionWeight int = 2
thirdPartyActionWeight int = 8
normalWeight int = gitHubOwnedActionWeight + thirdPartyActionWeight

// depTypeKey is the Values map key used to fetch the dependency type.
depTypeKey = "dependencyType"
)

func ruleRemToProbeRem(rem *rule.Remediation) *probe.Remediation {
return &probe.Remediation{
Patch: rem.Patch,
Text: rem.Text,
Markdown: rem.Markdown,
Effort: probe.RemediationEffort(rem.Effort),
}
}

func probeRemToRuleRem(rem *probe.Remediation) *rule.Remediation {
return &rule.Remediation{
Patch: rem.Patch,
Expand All @@ -72,128 +61,28 @@ func probeRemToRuleRem(rem *probe.Remediation) *rule.Remediation {
}
}

func dependenciesToFindings(r *checker.PinningDependenciesData) ([]finding.Finding, error) {
findings := make([]finding.Finding, 0)

for i := range r.ProcessingErrors {
e := r.ProcessingErrors[i]
f := finding.Finding{
Message: generateTextIncompleteResults(e),
Location: &e.Location,
Outcome: finding.OutcomeNotAvailable,
}
findings = append(findings, f)
}

for i := range r.Dependencies {
rr := r.Dependencies[i]
if rr.Location == nil {
if rr.Msg == nil {
e := sce.WithMessage(sce.ErrScorecardInternal, "empty File field")
return findings, e
}
f := &finding.Finding{
Probe: "",
Outcome: finding.OutcomeNotApplicable,
Message: *rr.Msg,
}
findings = append(findings, *f)
continue
}
if rr.Msg != nil {
loc := &finding.Location{
Type: rr.Location.Type,
Path: rr.Location.Path,
LineStart: &rr.Location.Offset,
LineEnd: &rr.Location.EndOffset,
Snippet: &rr.Location.Snippet,
}
f := &finding.Finding{
Probe: "",
Outcome: finding.OutcomeNotApplicable,
Message: *rr.Msg,
Location: loc,
}
findings = append(findings, *f)
continue
}
if rr.Pinned == nil {
loc := &finding.Location{
Type: rr.Location.Type,
Path: rr.Location.Path,
LineStart: &rr.Location.Offset,
LineEnd: &rr.Location.EndOffset,
Snippet: &rr.Location.Snippet,
}
f := &finding.Finding{
Probe: "",
Outcome: finding.OutcomeNotApplicable,
Message: fmt.Sprintf("%s has empty Pinned field", rr.Type),
Location: loc,
}
findings = append(findings, *f)
continue
}
if !*rr.Pinned {
loc := &finding.Location{
Type: rr.Location.Type,
Path: rr.Location.Path,
LineStart: &rr.Location.Offset,
LineEnd: &rr.Location.EndOffset,
Snippet: &rr.Location.Snippet,
}
f := &finding.Finding{
Probe: "",
Outcome: finding.OutcomeNegative,
Message: generateTextUnpinned(&rr),
Location: loc,
}
if rr.Remediation != nil {
f.Remediation = ruleRemToProbeRem(rr.Remediation)
}
f = f.WithValue(depTypeKey, string(rr.Type))
findings = append(findings, *f)
} else {
loc := &finding.Location{
Type: rr.Location.Type,
Path: rr.Location.Path,
LineStart: &rr.Location.Offset,
LineEnd: &rr.Location.EndOffset,
Snippet: &rr.Location.Snippet,
}
f := &finding.Finding{
Probe: "",
Outcome: finding.OutcomePositive,
Location: loc,
}
f = f.WithValue(depTypeKey, string(rr.Type))
findings = append(findings, *f)
}
}
return findings, nil
}

// PinningDependencies applies the score policy for the Pinned-Dependencies check.
func PinningDependencies(name string, c *checker.CheckRequest,
r *checker.PinningDependenciesData,
func PinningDependencies(name string,
findings []finding.Finding,
dl checker.DetailLogger,
) checker.CheckResult {
if r == nil {
e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data")
expectedProbes := []string{
pinsDependencies.Probe,
}

if !finding.UniqueProbesEqual(findings, expectedProbes) {
e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results")
return checker.CreateRuntimeErrorResult(name, e)
}

var wp workflowPinningResult
pr := make(map[checker.DependencyUseType]pinnedResult)
dl := c.Dlogger

findings, err := dependenciesToFindings(r)
if err != nil {
return checker.CreateRuntimeErrorResult(name, err)
}

for i := range findings {
f := findings[i]
switch f.Outcome {
case finding.OutcomeNotAvailable:
return checker.CreateInconclusiveResult(name, "no dependencies found")
case finding.OutcomeNotApplicable:
if f.Location != nil {
dl.Debug(&checker.LogMessage{
Expand Down Expand Up @@ -224,15 +113,15 @@ func PinningDependencies(name string, c *checker.CheckRequest,
lm.Remediation = probeRemToRuleRem(f.Remediation)
}
dl.Warn(lm)
case finding.OutcomeNotAvailable:
case finding.OutcomeError:
dl.Info(&checker.LogMessage{
Finding: &f,
})
continue
default:
// ignore
}
updatePinningResults(checker.DependencyUseType(f.Values[depTypeKey]),
updatePinningResults(checker.DependencyUseType(f.Values[pinsDependencies.DepTypeKey]),
f.Outcome, f.Location.Snippet,
&wp, pr)
}
Expand Down Expand Up @@ -289,21 +178,6 @@ func updatePinningResults(dependencyType checker.DependencyUseType,
pr[dependencyType] = p
}

func generateTextUnpinned(rr *checker.Dependency) string {
if rr.Type == checker.DependencyUseTypeGHAction {
// Check if we are dealing with a GitHub action or a third-party one.
gitHubOwned := fileparser.IsGitHubOwnedAction(rr.Location.Snippet)
owner := generateOwnerToDisplay(gitHubOwned)
return fmt.Sprintf("%s not pinned by hash", owner)
}

return fmt.Sprintf("%s not pinned by hash", rr.Type)
}

func generateTextIncompleteResults(e checker.ElementError) string {
return fmt.Sprintf("Possibly incomplete results: %s", e.Err)
}

func generateOwnerToDisplay(gitHubOwned bool) string {
if gitHubOwned {
return fmt.Sprintf("GitHub-owned %s", checker.DependencyUseTypeGHAction)
Expand Down
Loading

0 comments on commit 0cbcacb

Please sign in to comment.