Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into commit-depth
  • Loading branch information
ashearin committed Nov 13, 2023
2 parents 0813d0e + 934f170 commit 1c79121
Show file tree
Hide file tree
Showing 26 changed files with 767 additions and 164 deletions.
11 changes: 10 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
rebase-strategy: disabled
commit-message:
prefix: ":seedling:"
groups:
github-actions:
patterns:
- "*"
# These actions directly influence the build process and are excluded from grouped updates
exclude-patterns:
- "actions/setup-go"
- "arduino/setup-protoc"
- "goreleaser/goreleaser-action"
- package-ecosystem: docker
directory: "/"
schedule:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/depsreview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: 'Dependency Review'
uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034
uses: actions/dependency-review-action@fde92acd0840415674c16b39c7d703fc28bc511e
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
fetch-depth: 2 # needed to diff changed files
- id: files
name: Get changed files
uses: tj-actions/changed-files@95690f9ece77c1740f4a55b7f1de9023ed6b1f87 #v39.2.3
uses: tj-actions/changed-files@25ef3926d147cd02fc7e931c1ef50772bbb0d25d #v40.1.1
with:
files_ignore: '**.md'
- id: docs_only_check
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
permissions: read-all
steps:
- name: Install the verifier
uses: slsa-framework/slsa-verifier/actions/[email protected].0
uses: slsa-framework/slsa-verifier/actions/[email protected].1

- name: Download assets
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publishimage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
make install
make scorecard-ko
- name: Install Cosign
uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19
uses: sigstore/cosign-installer@1fc5bd396d372bee37d608f955b336615edf79c8
- name: Sign image
run: |
cosign sign --yes ghcr.io/${{github.repository_owner}}/scorecard/v4:${{ github.sha }}
2 changes: 1 addition & 1 deletion .github/workflows/slsa-goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
permissions: read-all
steps:
- name: Install the verifier
uses: slsa-framework/slsa-verifier/actions/[email protected].0
uses: slsa-framework/slsa-verifier/actions/[email protected].1

- name: Download the artifact
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ jobs:

- name: Verifier action
id: verifier
uses: kubernetes-sigs/kubebuilder-release-tools@d8367c29de8af903319d3a76de2436672515729b # v0.4.0
uses: kubernetes-sigs/kubebuilder-release-tools@3c3411345eedc489d1022288aa844691e92a9c29 # v0.4.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
38 changes: 31 additions & 7 deletions checker/raw_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
package checker

import (
"fmt"
"time"

"github.com/ossf/scorecard/v4/clients"
"github.com/ossf/scorecard/v4/finding"
"github.com/ossf/scorecard/v4/rule"
)

// RawResults contains results before a policy
Expand Down Expand Up @@ -111,19 +113,21 @@ const (

// PinningDependenciesData represents pinned dependency data.
type PinningDependenciesData struct {
Dependencies []Dependency
Dependencies []Dependency
ProcessingErrors []ElementError // jobs or files with errors may have incomplete results
}

// Dependency represents a dependency.
type Dependency struct {
// TODO: unique dependency name.
// TODO: Job *WorkflowJob
Name *string
PinnedAt *string
Location *File
Msg *string // Only for debug messages.
Pinned *bool
Type DependencyUseType
Name *string
PinnedAt *string
Location *File
Msg *string // Only for debug messages.
Pinned *bool
Remediation *rule.Remediation
Type DependencyUseType
}

// MaintainedData contains the raw results
Expand Down Expand Up @@ -437,3 +441,23 @@ func (f *File) Location() *finding.Location {

return loc
}

// ElementError allows us to identify the "element" that led to the given error.
// The "element" is the specific "code under analysis" that caused the error. It should
// describe what caused the error as precisely as possible.
//
// For example, if a shell parsing error occurs while parsing a Dockerfile `RUN` block
// or a GitHub workflow's `run:` step, the "element" should point to the Dockerfile
// lines or workflow job step that caused the failure, not just the file path.
type ElementError struct {
Err error
Location finding.Location
}

func (e *ElementError) Error() string {
return fmt.Sprintf("%s: %v", e.Err, e.Location)
}

func (e *ElementError) Unwrap() error {
return e.Err
}
36 changes: 18 additions & 18 deletions checks/evaluation/pinned_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import (
"github.com/ossf/scorecard/v4/checker"
"github.com/ossf/scorecard/v4/checks/fileparser"
sce "github.com/ossf/scorecard/v4/errors"
"github.com/ossf/scorecard/v4/remediation"
"github.com/ossf/scorecard/v4/rule"
"github.com/ossf/scorecard/v4/finding"
)

type pinnedResult struct {
Expand Down Expand Up @@ -62,8 +61,16 @@ func PinningDependencies(name string, c *checker.CheckRequest,
var wp worklowPinningResult
pr := make(map[checker.DependencyUseType]pinnedResult)
dl := c.Dlogger
//nolint:errcheck
remediationMetadata, _ := remediation.New(c)

for _, e := range r.ProcessingErrors {
e := e
dl.Info(&checker.LogMessage{
Finding: &finding.Finding{
Message: generateTextIncompleteResults(e),
Location: &e.Location,
},
})
}

for i := range r.Dependencies {
rr := r.Dependencies[i]
Expand Down Expand Up @@ -105,9 +112,9 @@ func PinningDependencies(name string, c *checker.CheckRequest,
Type: rr.Location.Type,
Offset: rr.Location.Offset,
EndOffset: rr.Location.EndOffset,
Text: generateText(&rr),
Text: generateTextUnpinned(&rr),
Snippet: rr.Location.Snippet,
Remediation: generateRemediation(remediationMetadata, &rr),
Remediation: rr.Remediation,
})
}
// Update the pinning status.
Expand Down Expand Up @@ -148,17 +155,6 @@ func PinningDependencies(name string, c *checker.CheckRequest,
"dependency not pinned by hash detected", score, checker.MaxResultScore)
}

func generateRemediation(remediationMd *remediation.RemediationMetadata, rr *checker.Dependency) *rule.Remediation {
switch rr.Type {
case checker.DependencyUseTypeGHAction:
return remediationMd.CreateWorkflowPinningRemediation(rr.Location.Path)
case checker.DependencyUseTypeDockerfileContainerImage:
return remediation.CreateDockerfilePinningRemediation(rr, remediation.CraneDigester{})
default:
return nil
}
}

func updatePinningResults(rr *checker.Dependency,
wp *worklowPinningResult, pr map[checker.DependencyUseType]pinnedResult,
) {
Expand All @@ -176,7 +172,7 @@ func updatePinningResults(rr *checker.Dependency,
pr[rr.Type] = p
}

func generateText(rr *checker.Dependency) string {
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)
Expand All @@ -187,6 +183,10 @@ func generateText(rr *checker.Dependency) string {
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
41 changes: 36 additions & 5 deletions checks/evaluation/pinned_dependencies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"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"
)

Expand Down Expand Up @@ -239,9 +240,10 @@ func Test_PinningDependencies(t *testing.T) {
t.Parallel()

tests := []struct {
name string
dependencies []checker.Dependency
expected scut.TestReturn
name string
dependencies []checker.Dependency
processingErrors []checker.ElementError
expected scut.TestReturn
}{
{
name: "all dependencies pinned",
Expand Down Expand Up @@ -796,6 +798,34 @@ func Test_PinningDependencies(t *testing.T) {
NumberOfDebug: 0,
},
},
{
name: "Skipped objects and dependencies",
dependencies: []checker.Dependency{
{
Location: &checker.File{},
Type: checker.DependencyUseTypeNpmCommand,
Pinned: asBoolPointer(false),
},
{
Location: &checker.File{},
Type: checker.DependencyUseTypeNpmCommand,
Pinned: asBoolPointer(false),
},
},
processingErrors: []checker.ElementError{
{
Err: sce.ErrJobOSParsing,
Location: finding.Location{},
},
},
expected: scut.TestReturn{
Error: nil,
Score: 0,
NumberOfWarn: 2, // unpinned deps
NumberOfInfo: 2, // 1 for npm deps, 1 for processing error
NumberOfDebug: 0,
},
},
}

for _, tt := range tests {
Expand All @@ -807,7 +837,8 @@ func Test_PinningDependencies(t *testing.T) {
c := checker.CheckRequest{Dlogger: &dl}
actual := PinningDependencies("checkname", &c,
&checker.PinningDependenciesData{
Dependencies: tt.dependencies,
Dependencies: tt.dependencies,
ProcessingErrors: tt.processingErrors,
})

if !scut.ValidateTestReturn(t, tt.name, &tt.expected, &actual, &dl) {
Expand Down Expand Up @@ -990,7 +1021,7 @@ func TestGenerateText(t *testing.T) {

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := generateText(tc.dependency)
result := generateTextUnpinned(tc.dependency)
if !cmp.Equal(tc.expectedText, result) {
t.Errorf("generateText mismatch (-want +got):\n%s", cmp.Diff(tc.expectedText, result))
}
Expand Down
11 changes: 9 additions & 2 deletions checks/fileparser/github_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,15 @@ func GetOSesForJob(job *actionlint.Job) ([]string, error) {
}

if len(jobOSes) == 0 {
return jobOSes, sce.WithMessage(sce.ErrScorecardInternal,
fmt.Sprintf("unable to determine OS for job: %v", GetJobName(job)))
// This error is caught by the caller, which is responsible for adding more
// precise location information
jobName := GetJobName(job)
return jobOSes, &checker.ElementError{
Location: finding.Location{
Snippet: &jobName,
},
Err: sce.ErrJobOSParsing,
}
}
return jobOSes, nil
}
Expand Down
Loading

0 comments on commit 1c79121

Please sign in to comment.