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

🌱 Convert pinned dependencies to probe #3829

Merged
merged 14 commits into from
Feb 26, 2024
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 @@
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 @@
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 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")

Check warning on line 74 in checks/evaluation/pinned_dependencies.go

View check run for this annotation

Codecov / codecov/patch

checks/evaluation/pinned_dependencies.go#L74

Added line #L74 was not covered by tests
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")

Check warning on line 85 in checks/evaluation/pinned_dependencies.go

View check run for this annotation

Codecov / codecov/patch

checks/evaluation/pinned_dependencies.go#L84-L85

Added lines #L84 - L85 were not covered by tests
AdamKorcz marked this conversation as resolved.
Show resolved Hide resolved
case finding.OutcomeNotApplicable:
if f.Location != nil {
dl.Debug(&checker.LogMessage{
Expand Down Expand Up @@ -224,15 +113,15 @@
lm.Remediation = probeRemToRuleRem(f.Remediation)
}
dl.Warn(lm)
case finding.OutcomeNotAvailable:
case finding.OutcomeError:

Check warning on line 116 in checks/evaluation/pinned_dependencies.go

View check run for this annotation

Codecov / codecov/patch

checks/evaluation/pinned_dependencies.go#L116

Added line #L116 was not covered by tests
spencerschrock marked this conversation as resolved.
Show resolved Hide resolved
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 @@
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 {
AdamKorcz marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Sprintf("GitHub-owned %s", checker.DependencyUseTypeGHAction)
Expand Down
Loading
Loading