diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml index f5bdbc7a0c4..0d23eff4f13 100644 --- a/.github/workflows/goreleaser.yaml +++ b/.github/workflows/goreleaser.yaml @@ -72,7 +72,7 @@ jobs: actions: read # To read the workflow path. id-token: write # To sign the provenance. contents: write # To add assets to a release. - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.5.0 with: base64-subjects: "${{ needs.goreleaser.outputs.hashes }}" upload-assets: true # upload to a new release diff --git a/.github/workflows/slsa-goreleaser.yml b/.github/workflows/slsa-goreleaser.yml index 4d7fa033dfd..52a7b7e9c03 100644 --- a/.github/workflows/slsa-goreleaser.yml +++ b/.github/workflows/slsa-goreleaser.yml @@ -29,7 +29,7 @@ jobs: contents: write actions: read needs: args - uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@bdd89e60dc5387d8f819bebc702987956bcd4913 # v1.2.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@v1.5.0 # v1.2.0 with: go-version: 1.19 evaluated-envs: "VERSION_LDFLAGS:${{needs.args.outputs.ldflags}}" diff --git a/checks/evaluation/cii_best_practices.go b/checks/evaluation/cii_best_practices.go index 61d3a98865b..0d8e5dcef26 100644 --- a/checks/evaluation/cii_best_practices.go +++ b/checks/evaluation/cii_best_practices.go @@ -32,7 +32,7 @@ const ( ) // CIIBestPractices applies the score policy for the CIIBestPractices check. -func CIIBestPractices(name string, dl checker.DetailLogger, r *checker.CIIBestPracticesData) checker.CheckResult { +func CIIBestPractices(name string, _ checker.DetailLogger, r *checker.CIIBestPracticesData) checker.CheckResult { if r == nil { e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") return checker.CreateRuntimeErrorResult(name, e) diff --git a/checks/evaluation/cii_best_practices_test.go b/checks/evaluation/cii_best_practices_test.go new file mode 100644 index 00000000000..d1798bfa72b --- /dev/null +++ b/checks/evaluation/cii_best_practices_test.go @@ -0,0 +1,86 @@ +// 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 evaluation + +import ( + "testing" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" +) + +func TestCIIBestPractices(t *testing.T) { + t.Run("CIIBestPractices", func(t *testing.T) { + t.Run("in progress", func(t *testing.T) { + r := &checker.CIIBestPracticesData{ + Badge: clients.InProgress, + } + result := CIIBestPractices("CIIBestPractices", nil, r) + if result.Score != inProgressScore { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, inProgressScore) + } + }) + t.Run("passing", func(t *testing.T) { + r := &checker.CIIBestPracticesData{ + Badge: clients.Passing, + } + result := CIIBestPractices("CIIBestPractices", nil, r) + if result.Score != passingScore { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, passingScore) + } + }) + t.Run("silver", func(t *testing.T) { + r := &checker.CIIBestPracticesData{ + Badge: clients.Silver, + } + result := CIIBestPractices("CIIBestPractices", nil, r) + if result.Score != silverScore { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, silverScore) + } + }) + t.Run("gold", func(t *testing.T) { + r := &checker.CIIBestPracticesData{ + Badge: clients.Gold, + } + result := CIIBestPractices("CIIBestPractices", nil, r) + if result.Score != checker.MaxResultScore { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, checker.MaxResultScore) + } + }) + t.Run("not found", func(t *testing.T) { + r := &checker.CIIBestPracticesData{ + Badge: clients.NotFound, + } + result := CIIBestPractices("CIIBestPractices", nil, r) + if result.Score != checker.MinResultScore { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, checker.MinResultScore) + } + }) + t.Run("error", func(t *testing.T) { + r := &checker.CIIBestPracticesData{ + Badge: clients.Unknown, + } + result := CIIBestPractices("CIIBestPractices", nil, r) + if result.Score != -1 { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, -1) + } + }) + t.Run("nil response", func(t *testing.T) { + result := CIIBestPractices("CIIBestPractices", nil, nil) + if result.Score != -1 { + t.Errorf("CIIBestPractices() = %v, want %v", result.Score, -1) + } + }) + }) +} diff --git a/checks/evaluation/dangerous_workflow_test.go b/checks/evaluation/dangerous_workflow_test.go new file mode 100644 index 00000000000..7726f33a64b --- /dev/null +++ b/checks/evaluation/dangerous_workflow_test.go @@ -0,0 +1,157 @@ +// 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 evaluation + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + scut "github.com/ossf/scorecard/v4/utests" +) + +func TestDangerousWorkflow(t *testing.T) { + t.Parallel() + type args struct { //nolint:govet + name string + dl checker.DetailLogger + r *checker.DangerousWorkflowData + } + tests := []struct { + name string + args args + want checker.CheckResult + }{ + { + name: "DangerousWorkflow - empty", + args: args{ + name: "DangerousWorkflow", + dl: &scut.TestDetailLogger{}, + r: &checker.DangerousWorkflowData{}, + }, + want: checker.CheckResult{ + Score: 10, + Reason: "no dangerous workflow patterns detected", + Version: 2, + Name: "DangerousWorkflow", + }, + }, + { + name: "DangerousWorkflow - Dangerous workflow detected", + args: args{ + name: "DangerousWorkflow", + dl: &scut.TestDetailLogger{}, + r: &checker.DangerousWorkflowData{ + Workflows: []checker.DangerousWorkflow{ + { + Type: checker.DangerousWorkflowUntrustedCheckout, + File: checker.File{ + Path: "a", + Snippet: "a", + Offset: 0, + EndOffset: 0, + Type: 0, + }, + }, + }, + }, + }, + want: checker.CheckResult{ + Score: 0, + Reason: "dangerous workflow patterns detected", + Version: 2, + Name: "DangerousWorkflow", + }, + }, + { + name: "DangerousWorkflow - Script injection detected", + args: args{ + name: "DangerousWorkflow", + dl: &scut.TestDetailLogger{}, + r: &checker.DangerousWorkflowData{ + Workflows: []checker.DangerousWorkflow{ + { + Type: checker.DangerousWorkflowScriptInjection, + File: checker.File{ + Path: "a", + Snippet: "a", + Offset: 0, + EndOffset: 0, + Type: 0, + }, + }, + }, + }, + }, + want: checker.CheckResult{ + Score: 0, + Reason: "dangerous workflow patterns detected", + Version: 2, + Name: "DangerousWorkflow", + }, + }, + { + name: "DangerousWorkflow - unknown type", + args: args{ + name: "DangerousWorkflow", + dl: &scut.TestDetailLogger{}, + r: &checker.DangerousWorkflowData{ + Workflows: []checker.DangerousWorkflow{ + { + Type: "foobar", + File: checker.File{ + Path: "a", + Snippet: "a", + Offset: 0, + EndOffset: 0, + Type: 0, + }, + }, + }, + }, + }, + want: checker.CheckResult{ + Score: -1, + Reason: "internal error: invalid type", + Version: 2, + Name: "DangerousWorkflow", + }, + }, + { + name: "DangerousWorkflow - nil data", + args: args{ + name: "DangerousWorkflow", + dl: &scut.TestDetailLogger{}, + r: nil, + }, + want: checker.CheckResult{ + Score: -1, + Reason: "internal error: empty raw data", + Name: "DangerousWorkflow", + Version: 2, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := DangerousWorkflow(tt.args.name, tt.args.dl, tt.args.r); !cmp.Equal(got, tt.want, cmpopts.IgnoreFields(checker.CheckResult{}, "Error")) { //nolint:lll + t.Errorf("DangerousWorkflow() = %v, want %v", got, cmp.Diff(got, tt.want, cmpopts.IgnoreFields(checker.CheckResult{}, "Error"))) //nolint:lll + } + }) + } +} diff --git a/checks/evaluation/fuzzing_test.go b/checks/evaluation/fuzzing_test.go new file mode 100644 index 00000000000..89311490586 --- /dev/null +++ b/checks/evaluation/fuzzing_test.go @@ -0,0 +1,104 @@ +// 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 evaluation + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + scut "github.com/ossf/scorecard/v4/utests" +) + +func TestFuzzing(t *testing.T) { + t.Parallel() + type args struct { //nolint + name string + dl checker.DetailLogger + r *checker.FuzzingData + } + tests := []struct { + name string + args args + want checker.CheckResult + }{ + { + name: "Fuzzing - no fuzzing", + args: args{ + name: "Fuzzing", + dl: &scut.TestDetailLogger{}, + r: &checker.FuzzingData{}, + }, + want: checker.CheckResult{ + Score: 0, + Name: "Fuzzing", + Version: 2, + Reason: "project is not fuzzed", + }, + }, + { + name: "Fuzzing - fuzzing", + args: args{ + name: "Fuzzing", + dl: &scut.TestDetailLogger{}, + r: &checker.FuzzingData{ + Fuzzers: []checker.Tool{ + { + Name: "Fuzzing", + Files: []checker.File{ + { + Path: "Fuzzing", + Type: 0, + Offset: 1, + Snippet: "Fuzzing", + }, + }, + }, + }, + }, + }, + want: checker.CheckResult{ + Score: 10, + Name: "Fuzzing", + Version: 2, + Reason: "project is fuzzed with [Fuzzing]", + }, + }, + { + name: "Fuzzing - fuzzing data nil", + args: args{ + name: "Fuzzing", + dl: &scut.TestDetailLogger{}, + r: nil, + }, + want: checker.CheckResult{ + Score: -1, + Name: "Fuzzing", + Version: 2, + Reason: "internal error: empty raw data", + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := Fuzzing(tt.args.name, tt.args.dl, tt.args.r); !cmp.Equal(got, tt.want, cmpopts.IgnoreFields(checker.CheckResult{}, "Error")) { //nolint:lll + t.Errorf("Fuzzing() = %v, want %v", got, cmp.Diff(got, tt.want, cmpopts.IgnoreFields(checker.CheckResult{}, "Error"))) //nolint:lll + } + }) + } +}