From 87c2d3c1da240c8f9d1e1d5a319972cb85013e0a Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Mon, 13 Nov 2023 18:35:29 +0000 Subject: [PATCH 01/51] :warning: Remove OneFuzz from fuzzing checks (#3666) This is removed because OneFuzz has been archived https://github.com/microsoft/onefuzz Signed-off-by: David Korczynski --- checks/evaluation/fuzzing.go | 2 - checks/evaluation/fuzzing_test.go | 18 +--- checks/fuzzing_test.go | 6 +- checks/raw/fuzzing.go | 32 ------ checks/raw/fuzzing_test.go | 59 ----------- docs/checks.md | 1 - docs/checks/internal/checks.yaml | 1 - e2e/fuzzing_test.go | 2 +- probes/entries.go | 2 - probes/fuzzedWithOneFuzz/def.yml | 32 ------ probes/fuzzedWithOneFuzz/impl.go | 39 ------- probes/fuzzedWithOneFuzz/impl_test.go | 144 -------------------------- 12 files changed, 5 insertions(+), 333 deletions(-) delete mode 100644 probes/fuzzedWithOneFuzz/def.yml delete mode 100644 probes/fuzzedWithOneFuzz/impl.go delete mode 100644 probes/fuzzedWithOneFuzz/impl_test.go diff --git a/checks/evaluation/fuzzing.go b/checks/evaluation/fuzzing.go index 132dda90df3..4b8308eaa23 100644 --- a/checks/evaluation/fuzzing.go +++ b/checks/evaluation/fuzzing.go @@ -24,7 +24,6 @@ import ( "github.com/ossf/scorecard/v4/probes/fuzzedWithGoNative" "github.com/ossf/scorecard/v4/probes/fuzzedWithJavaJazzerFuzzer" "github.com/ossf/scorecard/v4/probes/fuzzedWithOSSFuzz" - "github.com/ossf/scorecard/v4/probes/fuzzedWithOneFuzz" "github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedHaskell" "github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedJavascript" "github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedTypescript" @@ -47,7 +46,6 @@ func Fuzzing(name string, fuzzedWithRustCargofuzz.Probe, fuzzedWithSwiftLibFuzzer.Probe, fuzzedWithJavaJazzerFuzzer.Probe, - fuzzedWithOneFuzz.Probe, fuzzedWithOSSFuzz.Probe, fuzzedWithPropertyBasedHaskell.Probe, fuzzedWithPropertyBasedJavascript.Probe, diff --git a/checks/evaluation/fuzzing_test.go b/checks/evaluation/fuzzing_test.go index 85018eadb25..5c06f49da73 100644 --- a/checks/evaluation/fuzzing_test.go +++ b/checks/evaluation/fuzzing_test.go @@ -64,10 +64,6 @@ func TestFuzzing(t *testing.T) { Probe: "fuzzedWithJavaJazzerFuzzer", Outcome: finding.OutcomeNegative, }, - { - Probe: "fuzzedWithOneFuzz", - Outcome: finding.OutcomeNegative, - }, { Probe: "fuzzedWithOSSFuzz", Outcome: finding.OutcomeNegative, @@ -87,7 +83,7 @@ func TestFuzzing(t *testing.T) { }, result: scut.TestReturn{ Score: checker.MinResultScore, - NumberOfWarn: 13, + NumberOfWarn: 12, }, }, { @@ -125,10 +121,6 @@ func TestFuzzing(t *testing.T) { Probe: "fuzzedWithJavaJazzerFuzzer", Outcome: finding.OutcomeNegative, }, - { - Probe: "fuzzedWithOneFuzz", - Outcome: finding.OutcomeNegative, - }, { Probe: "fuzzedWithOSSFuzz", Outcome: finding.OutcomeNegative, @@ -159,10 +151,6 @@ func TestFuzzing(t *testing.T) { Probe: "fuzzedWithClusterFuzzLite", Outcome: finding.OutcomeNegative, }, - { - Probe: "fuzzedWithOneFuzz", - Outcome: finding.OutcomeNegative, - }, { Probe: "fuzzedWithOSSFuzz", Outcome: finding.OutcomeNegative, @@ -196,10 +184,6 @@ func TestFuzzing(t *testing.T) { Probe: "fuzzedWithGoNative", Outcome: finding.OutcomePositive, }, - { - Probe: "fuzzedWithOneFuzz", - Outcome: finding.OutcomeNegative, - }, { Probe: "fuzzedWithOSSFuzz", Outcome: finding.OutcomeNegative, diff --git a/checks/fuzzing_test.go b/checks/fuzzing_test.go index dd2f3a17994..6b031fa5c30 100644 --- a/checks/fuzzing_test.go +++ b/checks/fuzzing_test.go @@ -53,7 +53,7 @@ func TestFuzzing(t *testing.T) { wantErr: false, expected: scut.TestReturn{ Error: nil, - NumberOfWarn: 13, + NumberOfWarn: 12, NumberOfDebug: 0, NumberOfInfo: 0, Score: 0, @@ -110,7 +110,7 @@ func TestFuzzing(t *testing.T) { wantFuzzErr: false, expected: scut.TestReturn{ Error: nil, - NumberOfWarn: 13, + NumberOfWarn: 12, NumberOfDebug: 0, NumberOfInfo: 0, Score: 0, @@ -121,7 +121,7 @@ func TestFuzzing(t *testing.T) { wantFuzzErr: true, expected: scut.TestReturn{ Error: nil, - NumberOfWarn: 13, + NumberOfWarn: 12, NumberOfDebug: 0, NumberOfInfo: 0, Score: 0, diff --git a/checks/raw/fuzzing.go b/checks/raw/fuzzing.go index efd61a53915..a260fcf42a5 100644 --- a/checks/raw/fuzzing.go +++ b/checks/raw/fuzzing.go @@ -30,7 +30,6 @@ import ( const ( fuzzerOSSFuzz = "OSSFuzz" fuzzerClusterFuzzLite = "ClusterFuzzLite" - oneFuzz = "OneFuzz" fuzzerBuiltInGo = "GoBuiltInFuzzer" fuzzerPropertyBasedHaskell = "HaskellPropertyBasedTesting" fuzzerPropertyBasedJavaScript = "JavaScriptPropertyBasedTesting" @@ -181,21 +180,6 @@ func Fuzzing(c *checker.CheckRequest) (checker.FuzzingData, error) { ) } - usingOneFuzz, e := checkOneFuzz(c) - if e != nil { - return checker.FuzzingData{}, fmt.Errorf("%w", e) - } - if usingOneFuzz { - fuzzers = append(fuzzers, - checker.Tool{ - Name: oneFuzz, - URL: asPointer("https://github.com/microsoft/onefuzz"), - Desc: asPointer("Enables continuous developer-driven fuzzing to proactively harden software prior to release."), - // TODO: File. - }, - ) - } - usingOSSFuzz, e := checkOSSFuzz(c) if e != nil { return checker.FuzzingData{}, fmt.Errorf("%w", e) @@ -251,22 +235,6 @@ func checkCFLite(c *checker.CheckRequest) (bool, error) { return result, nil } -func checkOneFuzz(c *checker.CheckRequest) (bool, error) { - result := false - e := fileparser.OnMatchingFileContentDo(c.RepoClient, fileparser.PathMatcher{ - Pattern: "^\\.onefuzz$", - CaseSensitive: true, - }, func(path string, content []byte, args ...interface{}) (bool, error) { - result = true - return false, nil - }, nil) - if e != nil { - return result, fmt.Errorf("%w", e) - } - - return result, nil -} - func checkOSSFuzz(c *checker.CheckRequest) (bool, error) { if c.OssFuzzRepo == nil { return false, nil diff --git a/checks/raw/fuzzing_test.go b/checks/raw/fuzzing_test.go index fc8651a3dc3..d2b855c30e1 100644 --- a/checks/raw/fuzzing_test.go +++ b/checks/raw/fuzzing_test.go @@ -103,65 +103,6 @@ func Test_checkOSSFuzz(t *testing.T) { } } -// Test_checkOneFuzz is a test function for checkOneFuzz. -func Test_checkOneFuzz(t *testing.T) { - t.Parallel() - //nolint - tests := []struct { - name string - want bool - wantErr bool - fileName []string - }{ - { - name: "Test_checkOneFuzz success", - want: true, - wantErr: false, - fileName: []string{".onefuzz"}, - }, - { - name: "Test_checkOneFuzz not found", - want: false, - wantErr: false, - fileName: []string{}, - }, - { - name: "Test_checkOneFuzz failure", - want: false, - wantErr: true, - fileName: []string{".onefuzz"}, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - ctrl := gomock.NewController(t) - defer ctrl.Finish() - mockFuzz := mockrepo.NewMockRepoClient(ctrl) - mockFuzz.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() - mockFuzz.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) (string, error) { - if tt.wantErr { - //nolint - return "", errors.New("error") - } - return "", nil - }).AnyTimes() - req := checker.CheckRequest{ - RepoClient: mockFuzz, - } - got, err := checkOneFuzz(&req) - if (err != nil) != tt.wantErr { - t.Errorf("checkOneFuzz() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("checkOneFuzz() = %v, want %v for test %v", got, tt.want, tt.name) - } - }) - } -} - // Test_checkCFLite is a test function for checkCFLite. func Test_checkCFLite(t *testing.T) { t.Parallel() diff --git a/docs/checks.md b/docs/checks.md index 88248e88d66..9a8fa379866 100644 --- a/docs/checks.md +++ b/docs/checks.md @@ -342,7 +342,6 @@ This check tries to determine if the project uses - currently only supports [Go fuzzing](https://go.dev/doc/fuzz/), - a limited set of property-based testing libraries for Haskell including [QuickCheck](https://hackage.haskell.org/package/QuickCheck), [Hedgehog](https://hedgehog.qa/), [validity](https://hackage.haskell.org/package/validity) or [SmallCheck](https://hackage.haskell.org/package/smallcheck), - a limited set of property-based testing libraries for JavaScript and TypeScript including [fast-check](https://fast-check.dev/). -4. if it contains a [OneFuzz](https://github.com/microsoft/onefuzz) integration [detection file](https://github.com/microsoft/onefuzz/blob/main/docs/getting-started.md#detecting-the-use-of-onefuzz); Fuzzing, or fuzz testing, is the practice of feeding unexpected or random data into a program to expose bugs. Regular fuzzing is important to detect diff --git a/docs/checks/internal/checks.yaml b/docs/checks/internal/checks.yaml index 5d08a6ce9a3..2ec49840581 100644 --- a/docs/checks/internal/checks.yaml +++ b/docs/checks/internal/checks.yaml @@ -402,7 +402,6 @@ checks: - currently only supports [Go fuzzing](https://go.dev/doc/fuzz/), - a limited set of property-based testing libraries for Haskell including [QuickCheck](https://hackage.haskell.org/package/QuickCheck), [Hedgehog](https://hedgehog.qa/), [validity](https://hackage.haskell.org/package/validity) or [SmallCheck](https://hackage.haskell.org/package/smallcheck), - a limited set of property-based testing libraries for JavaScript and TypeScript including [fast-check](https://fast-check.dev/). - 4. if it contains a [OneFuzz](https://github.com/microsoft/onefuzz) integration [detection file](https://github.com/microsoft/onefuzz/blob/main/docs/getting-started.md#detecting-the-use-of-onefuzz); Fuzzing, or fuzz testing, is the practice of feeding unexpected or random data into a program to expose bugs. Regular fuzzing is important to detect diff --git a/e2e/fuzzing_test.go b/e2e/fuzzing_test.go index 25935731092..c93c951e497 100644 --- a/e2e/fuzzing_test.go +++ b/e2e/fuzzing_test.go @@ -192,7 +192,7 @@ var _ = Describe("E2E TEST:"+checks.CheckFuzzing, func() { expected := scut.TestReturn{ Error: nil, Score: checker.MinResultScore, - NumberOfWarn: 13, + NumberOfWarn: 12, NumberOfInfo: 0, NumberOfDebug: 0, } diff --git a/probes/entries.go b/probes/entries.go index c83e7338365..daec6474ce6 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -24,7 +24,6 @@ import ( "github.com/ossf/scorecard/v4/probes/fuzzedWithGoNative" "github.com/ossf/scorecard/v4/probes/fuzzedWithJavaJazzerFuzzer" "github.com/ossf/scorecard/v4/probes/fuzzedWithOSSFuzz" - "github.com/ossf/scorecard/v4/probes/fuzzedWithOneFuzz" "github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedHaskell" "github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedJavascript" "github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedTypescript" @@ -73,7 +72,6 @@ var ( } Fuzzing = []ProbeImpl{ fuzzedWithOSSFuzz.Run, - fuzzedWithOneFuzz.Run, fuzzedWithGoNative.Run, fuzzedWithPythonAtheris.Run, fuzzedWithCLibFuzzer.Run, diff --git a/probes/fuzzedWithOneFuzz/def.yml b/probes/fuzzedWithOneFuzz/def.yml deleted file mode 100644 index 8fb87a8f5ea..00000000000 --- a/probes/fuzzedWithOneFuzz/def.yml +++ /dev/null @@ -1,32 +0,0 @@ -# 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: fuzzedWithOneFuzz -short: Check that the project is fuzzed using OneFuzz -motivation: > - Fuzzing, or fuzz testing, is the practice of feeding unexpected or random data into a program to expose bugs. - Regular fuzzing is important to detect vulnerabilities that may be exploited by others, especially since attackers can also use fuzzing to find the same flaws. -implementation: > - The implementation checks if the file '.onefuzz' is present in the source code files. -outcome: - - If the file is found, one finding is returned with OutcomePositive (1). - - If the file is not found, one finding with OutcomeNegative (0) is returned. -remediation: - effort: High - text: - - Follow the steps in https://github.com/microsoft/onefuzz to start fuzzing for your project. - - Over time, try to add fuzzing for more functionalities of your project. - markdown: - - Follow the steps in [https://github.com/microsoft/onefuzz](https://github.com/microsoft/onefuzz) to start fuzzing for your project. - - Over time, try to add fuzzing for more functionalities of your project. \ No newline at end of file diff --git a/probes/fuzzedWithOneFuzz/impl.go b/probes/fuzzedWithOneFuzz/impl.go deleted file mode 100644 index bcc3645b3ff..00000000000 --- a/probes/fuzzedWithOneFuzz/impl.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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. - -// nolint:stylecheck -package fuzzedWithOneFuzz - -import ( - "embed" - "fmt" - - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/finding" - "github.com/ossf/scorecard/v4/probes/internal/utils/fuzzing" - "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" -) - -//go:embed *.yml -var fs embed.FS - -var Probe = "fuzzedWithOneFuzz" - -func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { - if raw == nil { - return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) - } - //nolint:wrapcheck - return fuzzing.Run(raw, fs, Probe, "OneFuzz") -} diff --git a/probes/fuzzedWithOneFuzz/impl_test.go b/probes/fuzzedWithOneFuzz/impl_test.go deleted file mode 100644 index f71fefda910..00000000000 --- a/probes/fuzzedWithOneFuzz/impl_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// 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. - -// nolint:stylecheck -package fuzzedWithOneFuzz - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/finding" - "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" -) - -func Test_Run(t *testing.T) { - t.Parallel() - // nolint:govet - tests := []struct { - name string - raw *checker.RawResults - outcomes []finding.Outcome - err error - }{ - { - name: "fuzzer present", - raw: &checker.RawResults{ - FuzzingResults: checker.FuzzingData{ - Fuzzers: []checker.Tool{ - { - Name: "OneFuzz", - }, - }, - }, - }, - outcomes: []finding.Outcome{ - finding.OutcomePositive, - }, - }, - { - name: "fuzzer present twice", - raw: &checker.RawResults{ - FuzzingResults: checker.FuzzingData{ - Fuzzers: []checker.Tool{ - { - Name: "OneFuzz", - }, - { - Name: "OneFuzz", - }, - }, - }, - }, - outcomes: []finding.Outcome{ - finding.OutcomePositive, - finding.OutcomePositive, - }, - }, - { - name: "fuzzer present and other present", - raw: &checker.RawResults{ - FuzzingResults: checker.FuzzingData{ - Fuzzers: []checker.Tool{ - { - Name: "OneFuzz", - }, - { - Name: "not-OneFuzz", - }, - }, - }, - }, - outcomes: []finding.Outcome{ - finding.OutcomePositive, - }, - }, - { - name: "fuzzer not present", - raw: &checker.RawResults{ - FuzzingResults: checker.FuzzingData{ - Fuzzers: []checker.Tool{ - { - Name: "not-OneFuzz", - }, - }, - }, - }, - outcomes: []finding.Outcome{ - finding.OutcomeNegative, - }, - }, - { - name: "no fuzzer", - raw: &checker.RawResults{}, - outcomes: []finding.Outcome{ - finding.OutcomeNegative, - }, - }, - { - name: "nil raw", - err: uerror.ErrNil, - }, - } - for _, tt := range tests { - tt := tt // Re-initializing variable so it is not changed while executing the closure below - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - findings, s, err := Run(tt.raw) - if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { - t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) - } - if err != nil { - return - } - if diff := cmp.Diff(Probe, s); diff != "" { - t.Errorf("mismatch (-want +got):\n%s", diff) - } - if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { - t.Errorf("mismatch (-want +got):\n%s", diff) - } - for i := range tt.outcomes { - outcome := &tt.outcomes[i] - f := &findings[i] - if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { - t.Errorf("mismatch (-want +got):\n%s", diff) - } - } - }) - } -} From 6dffe650007a62be5b357f009581370621b55872 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 10:58:51 -0800 Subject: [PATCH 02/51] :seedling: Bump github.com/sigstore/cosign/v2 from 2.1.1 to 2.2.1 in /tools (#3660) * :seedling: Bump github.com/sigstore/cosign/v2 in /tools Bumps [github.com/sigstore/cosign/v2](https://github.com/sigstore/cosign) from 2.1.1 to 2.2.1. - [Release notes](https://github.com/sigstore/cosign/releases) - [Changelog](https://github.com/sigstore/cosign/blob/main/CHANGELOG.md) - [Commits](https://github.com/sigstore/cosign/compare/v2.1.1...v2.2.1) --- updated-dependencies: - dependency-name: github.com/sigstore/cosign/v2 dependency-type: indirect ... Signed-off-by: dependabot[bot] * bump actions/dependency-review-action to v3.1.3 This PR is incompatible with v3.1.2 due to some of the modules being updated. See https://www.github.com/actions/dependency-review-action/issues/613 Signed-off-by: Spencer Schrock --------- Signed-off-by: dependabot[bot] Signed-off-by: Spencer Schrock Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Spencer Schrock --- .github/workflows/depsreview.yml | 2 +- tools/go.mod | 163 +++++++------- tools/go.sum | 354 +++++++++++++++---------------- 3 files changed, 258 insertions(+), 261 deletions(-) diff --git a/.github/workflows/depsreview.yml b/.github/workflows/depsreview.yml index e5deedb4050..e60f76647b0 100644 --- a/.github/workflows/depsreview.yml +++ b/.github/workflows/depsreview.yml @@ -24,4 +24,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: 'Dependency Review' - uses: actions/dependency-review-action@fde92acd0840415674c16b39c7d703fc28bc511e + uses: actions/dependency-review-action@7bbfa034e752445ea40215fff1c3bf9597993d3f # v3.1.3 diff --git a/tools/go.mod b/tools/go.mod index d237f81c987..294395dabca 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -15,12 +15,12 @@ require ( require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 4d63.com/gochecknoglobals v0.2.1 // indirect - cloud.google.com/go v0.110.7 // indirect - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go v0.110.9 // indirect + cloud.google.com/go/compute v1.23.2 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.1 // indirect - cloud.google.com/go/kms v1.15.0 // indirect - cloud.google.com/go/storage v1.31.0 // indirect + cloud.google.com/go/iam v1.1.4 // indirect + cloud.google.com/go/kms v1.15.4 // indirect + cloud.google.com/go/storage v1.33.0 // indirect code.gitea.io/sdk/gitea v0.15.1 // indirect dario.cat/mergo v1.0.0 // indirect github.com/4meepo/tagalign v1.3.3 // indirect @@ -30,9 +30,9 @@ require ( github.com/Antonboom/nilnil v0.1.7 // indirect github.com/Antonboom/testifylint v0.2.3 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 // indirect @@ -45,7 +45,7 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0 // indirect @@ -55,7 +55,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.1.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230626094100-7e9e0395ebec // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect github.com/acomagu/bufpipe v1.0.4 // indirect github.com/alecthomas/go-check-sumtype v0.1.3 // indirect github.com/alessio/shellescape v1.4.1 // indirect @@ -66,30 +66,30 @@ require ( github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect github.com/atc0005/go-teams-notify/v2 v2.8.0 // indirect - github.com/aws/aws-sdk-go v1.44.314 // indirect - github.com/aws/aws-sdk-go-v2 v1.20.0 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 // indirect - github.com/aws/aws-sdk-go-v2/config v1.18.32 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.31 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 // indirect + github.com/aws/aws-sdk-go v1.47.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.21.2 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 // indirect + github.com/aws/aws-sdk-go-v2/config v1.19.1 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.43 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.17.12 // indirect - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.13.12 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.24.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 // indirect - github.com/aws/smithy-go v1.14.0 // indirect - github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220802171026-617dc7abb2ea // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.24.7 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect + github.com/aws/smithy-go v1.15.0 // indirect + github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.1 // indirect @@ -110,15 +110,15 @@ require ( github.com/catenacyber/perfsprint v0.2.0 // indirect github.com/cavaliergopher/cpio v1.0.1 // indirect github.com/ccojocar/zxcvbn-go v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/charithe/durationcheck v0.0.10 // indirect github.com/charmbracelet/lipgloss v0.7.1 // indirect github.com/chavacava/garif v0.1.0 // indirect - github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect - github.com/cloudflare/circl v1.3.3 // indirect + github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect + github.com/cloudflare/circl v1.3.5 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/daixiang0/gci v0.11.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -131,10 +131,11 @@ require ( github.com/disgoorg/json v1.1.0 // indirect github.com/disgoorg/log v1.2.1 // indirect github.com/disgoorg/snowflake/v2 v2.0.1 // indirect - github.com/docker/cli v24.0.0+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/cli v24.0.7+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect @@ -146,17 +147,17 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/firefart/nonamedreturns v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/ghostiam/protogetter v0.2.3 // indirect github.com/go-critic/go-critic v0.9.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.4.1 // indirect github.com/go-git/go-git/v5 v5.7.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.3 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/errors v0.20.4 // indirect + github.com/go-openapi/jsonpointer v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect github.com/go-openapi/runtime v0.26.0 // indirect @@ -178,6 +179,7 @@ require ( github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect @@ -193,13 +195,13 @@ require ( github.com/google/go-containerregistry v0.16.1 // indirect github.com/google/go-github/v53 v53.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/google/rpmpack v0.5.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/google/wire v0.5.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 // indirect github.com/goreleaser/chglog v0.5.0 // indirect @@ -213,9 +215,9 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-version v1.6.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/iancoleman/orderedmap v0.2.0 // indirect @@ -233,7 +235,7 @@ require ( github.com/kisielk/errcheck v1.6.3 // indirect github.com/kisielk/gotool v1.0.0 // indirect github.com/kkHAIKE/contextcheck v1.1.4 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/kulti/thelper v0.6.3 // indirect github.com/kunwardeep/paralleltest v1.0.8 // indirect @@ -242,7 +244,7 @@ require ( github.com/ldez/gomoddirectives v0.2.3 // indirect github.com/ldez/tagliatelle v0.5.0 // indirect github.com/leonklingele/grouper v1.1.1 // indirect - github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect + github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/macabu/inamedparam v0.1.2 // indirect @@ -255,7 +257,7 @@ require ( github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-mastodon v0.0.6 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect github.com/mgechev/revive v1.3.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -284,10 +286,10 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polyfloyd/go-errorlint v1.4.5 // indirect - github.com/prometheus/client_golang v1.15.1 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quasilyte/go-ruleguard v0.4.0 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect @@ -302,13 +304,14 @@ require ( github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.24.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect github.com/securego/gosec/v2 v2.18.2 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/shopspring/decimal v1.2.0 // indirect - github.com/sigstore/cosign/v2 v2.1.1 // indirect - github.com/sigstore/rekor v1.2.2-0.20230530122220-67cc9e58bd23 // indirect - github.com/sigstore/sigstore v1.7.1 // indirect + github.com/sigstore/cosign/v2 v2.2.1 // indirect + github.com/sigstore/rekor v1.3.3 // indirect + github.com/sigstore/sigstore v1.7.5 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sivchari/nosnakecase v1.7.0 // indirect @@ -320,7 +323,7 @@ require ( github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.10.0 // indirect github.com/spf13/cast v1.5.1 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.17.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect @@ -332,7 +335,6 @@ require ( github.com/tdakkota/asciicheck v0.2.0 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/tetafro/godot v1.4.15 // indirect - github.com/theupdateframework/go-tuf v0.5.2 // indirect github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect github.com/timonwong/loggercheck v0.9.4 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect @@ -343,9 +345,9 @@ require ( github.com/ultraware/funlen v0.1.0 // indirect github.com/ultraware/whitespace v0.0.5 // indirect github.com/uudashr/gocognit v1.1.2 // indirect - github.com/vbatts/tar-split v0.11.3 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 // indirect - github.com/xanzy/go-gitlab v0.90.0 // indirect + github.com/xanzy/go-gitlab v0.93.2 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xen0n/gosmopolitan v1.2.2 // indirect github.com/yagipy/maintidx v1.0.0 // indirect @@ -354,49 +356,48 @@ require ( gitlab.com/bosi/decorder v0.4.1 // indirect gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect go-simpler.org/sloglint v0.1.2 // indirect - go.mongodb.org/mongo-driver v1.11.3 // indirect + go.mongodb.org/mongo-driver v1.12.1 // indirect go.opencensus.io v0.24.0 // indirect go.tmz.dev/musttag v0.7.2 // indirect - go.uber.org/atomic v1.11.0 // indirect go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - gocloud.dev v0.33.0 // indirect + go.uber.org/zap v1.26.0 // indirect + gocloud.dev v0.34.0 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sync v0.4.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.143.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect - google.golang.org/grpc v1.58.3 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/api v0.149.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/grpc v1.59.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.1.0 // indirect honnef.co/go/tools v0.4.6 // indirect - k8s.io/apimachinery v0.28.2 // indirect + k8s.io/apimachinery v0.28.3 // indirect k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect mvdan.cc/gofumpt v0.5.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect sigs.k8s.io/kind v0.20.0 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/tools/go.sum b/tools/go.sum index 144c413963f..0d3e1011b11 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -21,24 +21,24 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= +cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= +cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/kms v1.15.0 h1:xYl5WEaSekKYN5gGRyhjvZKM22GVBBCzegGNVPy+aIs= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= +cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= +cloud.google.com/go/kms v1.15.4 h1:gEZzC54ZBI+aeW8/jg9tgz9KR4Aa+WEDPbdGIV3iJ7A= +cloud.google.com/go/kms v1.15.4/go.mod h1:L3Sdj6QTHK8dfwK5D1JLsAyELsNMnd3tAIwGS4ltKpc= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -49,8 +49,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.31.0 h1:+S3LjjEN2zZ+L5hOwj4+1OkGCsLVe0NzpXKQ1pSdTCI= -cloud.google.com/go/storage v1.31.0/go.mod h1:81ams1PrhW16L4kF7qg+4mTq7SRs5HsbDTM0bWvrwJ0= +cloud.google.com/go/storage v1.33.0 h1:PVrDOkIC8qQVa1P3SXGpQvfuJhN2LHOoyZvWs8D2X5M= +cloud.google.com/go/storage v1.33.0/go.mod h1:Hhh/dogNRGca7IWv1RC2YqEn0c0G77ctA/OxflYkiD8= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= @@ -71,12 +71,12 @@ github.com/Antonboom/testifylint v0.2.3 h1:MFq9zyL+rIVpsvLX4vDPLojgN7qODzWsrnftN github.com/Antonboom/testifylint v0.2.3/go.mod h1:IYaXaOX9NbfAyO+Y04nfjGI8wDemC1rUyM/cYolz018= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.4.0 h1:TuEMD+E+1aTjjLICGQOW6vLe8UWES7kopac9mUXL56Y= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.4.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= @@ -110,11 +110,10 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -138,8 +137,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/OpenPeeDeeP/depguard/v2 v2.1.0 h1:aQl70G173h/GZYhWf36aE5H0KaujXfVMnn/f1kSDVYY= github.com/OpenPeeDeeP/depguard/v2 v2.1.0/go.mod h1:PUBgk35fX4i7JDmwzlJwJ+GMe6NfO1723wmJMgPThNQ= -github.com/ProtonMail/go-crypto v0.0.0-20230626094100-7e9e0395ebec h1:vV3RryLxt42+ZIVOFbYJCH1jsZNTNmj2NYru5zfx+4E= -github.com/ProtonMail/go-crypto v0.0.0-20230626094100-7e9e0395ebec/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE= +github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -174,77 +173,79 @@ github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5Fc github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= github.com/atc0005/go-teams-notify/v2 v2.8.0 h1:971J5qivrzBbYMDAdmW7v9s7W2u2jiIRVcY+LaIJqww= github.com/atc0005/go-teams-notify/v2 v2.8.0/go.mod h1:SIeE1UfCcVRYMqP5b+r1ZteHyA/2UAjzWF5COnZ8q0w= -github.com/aws/aws-sdk-go v1.44.314 h1:d/5Jyk/Fb+PBd/4nzQg0JuC2W4A0knrDIzBgK/ggAow= -github.com/aws/aws-sdk-go v1.44.314/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= -github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= -github.com/aws/aws-sdk-go-v2 v1.16.11/go.mod h1:WTACcleLz6VZTp7fak4EO5b9Q4foxbn+8PIz3PmyKlo= -github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8= +github.com/aws/aws-sdk-go v1.47.0 h1:/JUg9V1+xh+qBn8A6ec/l15ETPaMaBqxkjz+gg63dNk= +github.com/aws/aws-sdk-go v1.47.0/go.mod h1:DlEaEbWKZmsITVbqlSVvekPARM1HzeV9PMYg15ymSDA= github.com/aws/aws-sdk-go-v2 v1.20.0/go.mod h1:uWOr0m0jDsiWw8nnXiqZ+YG6LdvAlGYDLLf2NmHZoy4= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 h1:/MS8AzqYNAhhRNalOmxUvYs8VEbNGifTnzhPFdcRQkQ= +github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= +github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= +github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11/go.mod h1:va22++AdXht4ccO3kH2SHkHHYvZ2G9Utz+CXKmm2CaU= -github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E= -github.com/aws/aws-sdk-go-v2/config v1.18.32 h1:tqEOvkbTxwEV7hToRcJ1xZRjcATqwDVsWbAscgRKyNI= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM= github.com/aws/aws-sdk-go-v2/config v1.18.32/go.mod h1:U3ZF0fQRRA4gnbn9GGvOWLoT2EzzZfAWeKwnVrm1rDc= -github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk= -github.com/aws/aws-sdk-go-v2/credentials v1.13.31 h1:vJyON3lG7R8VOErpJJBclBADiWTwzcwdkQpTKx8D2sk= +github.com/aws/aws-sdk-go-v2/config v1.19.1 h1:oe3vqcGftyk40icfLymhhhNysAwk0NfiwkDi2GTPMXs= +github.com/aws/aws-sdk-go-v2/config v1.19.1/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= github.com/aws/aws-sdk-go-v2/credentials v1.13.31/go.mod h1:T4sESjBtY2lNxLgkIASmeP57b5j7hTQqCbqG0tWnxC4= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 h1:X3H6+SU21x+76LRglk21dFRgMTJMa5QcpW+SqUf5BBg= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7/go.mod h1:3we0V09SwcJBzNlnyovrR2wWJhWmVdqAsmVs4uronv8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76 h1:DJ1kHj0GI9BbX+XhF0kHxlzOVjcncmDUXmCvXdbfdAE= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76/go.mod h1:/AZCdswMSgwpB2yMSFfY5H4pVeBLnCuPehdmO/r3xSM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC3+FsKhNcCMJ7tUVj/8uSD5CZXeQ4wV6fM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18/go.mod h1:348MLhzV1GSlZSMusdwQpXKbhD7X2gbI/TxwAPKkYZQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 h1:zr/gxAZkMcvP71ZhQOcvdm8ReLjFgIXnIn0fw5AM7mo= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37/go.mod h1:Pdn4j43v49Kk6+82spO3Tu5gSeQXRsxo56ePPQAvFiA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9/go.mod h1:08tUpeSGN33QKSO7fwxXczNfiwCpbj+GxK6XKwqWVv0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12/go.mod h1:ckaCVTEdGAxO6KwTGzgskxR1xM+iJW4lxMyDFVda2Fc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 h1:0HCMIkAkVY9KMgueD8tf4bRTUanzEYvhw7KkPXIMpO0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31/go.mod h1:fTJDMe8LOFYtqiFFFeHA+SVMAwqLhoq0kcInYoLa9Js= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16/go.mod h1:CYmI+7x03jjJih8kBEEFKRQc40UjUokT0k7GbvrhhTc= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 h1:+i1DOFrW3YZ3apE45tCal9+aDKK6kNEbW6Ib7e1nFxE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38/go.mod h1:1/jLp0OgOaWIetycOmycW+vYTYgTZFPttJQRgsI1PoU= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 h1:U5yySdwt2HPo/pnQec04DImLzWORbeWML1fJiLkKruI= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0/go.mod h1:EhC/83j8/hL/UB1WmExo3gkElaja/KlmZM/gl1rTfjM= -github.com/aws/aws-sdk-go-v2/service/ecr v1.17.9/go.mod h1:fkIc4qe3SfQhPt/HAmDG7DJMjMBHElHV44axRyUSojA= -github.com/aws/aws-sdk-go-v2/service/ecr v1.17.12 h1:qBuF6exFzbKurzWqBR+7ptvnuKuWipm9LclsB7A/AUo= -github.com/aws/aws-sdk-go-v2/service/ecr v1.17.12/go.mod h1:/RTlDxrZR6VPGpVCydun5SbxzDciIJKiQUYF/EOpvXA= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.13.8/go.mod h1:nPSH6Ebmb3OkKl7+CLSjx+SMBaoFKbOe9mZhTAd352k= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.13.12 h1:JfDKV54iJuX2YE1NzzHMQ97LmC10ifgaW7BpqaNKzAg= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.13.12/go.mod h1:Hcfe3RBksYrl0fgSxZ4wvhSt6IiZBh+VlkaTKQLu9PE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 h1:uAiiHnWihGP2rVp64fHwzLDrswGjEjsPszwRYMiYQPU= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 h1:6lJvvkQ9HmbHZ4h/IEwclwv2mrTW8Uq1SOB/kXy0mfw= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4/go.mod h1:1PrKYwxTM+zjpw9Y41KFtoJCQrJ34Z47Y4VgVbfndjo= +github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2 h1:y6LX9GUoEA3mO0qpFl1ZQHj1rFyPWVphlzebiSt2tKE= +github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2/go.mod h1:Q0LcmaN/Qr8+4aSBrdrXXePqoX0eOuYpJLbYpilmWnA= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12/go.mod h1:fUTHpOXqRQpXvEpDPSa3zxCc2fnpW6YnBoba+eQr+Bg= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 h1:kvN1jPHr9UffqqG3bSgZ8tx4+1zKVHz/Ktw/BwW6hX8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 h1:m0QTSI6pZYJTk5WSKx3fm5cNW/DCicVzULBgU/6IyD0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14/go.mod h1:dDilntgHy9WnHXsh7dDtUPgHKEfTJIBUTHM8OWm0f/0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32/go.mod h1:QmMEM7es84EUkbYWcpnkx8i5EW2uERPfrTFeOch128Y= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9/go.mod h1:yQowTpvdZkFVuHrLBXmczat4W+WJKg/PafBZnGBLga0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 h1:auGDJ0aLZahF5SPvkJ6WcUuX7iQ7kyl2MamV7Tm8QBk= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 h1:eev2yZX7esGRjqRbnVk1UxMLw4CyVZDpZXRCcy75oQk= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36/go.mod h1:lGnOkH9NJATw0XEPcAknFBj3zzNTEGRHtSw+CwC1YTg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31/go.mod h1:3+lloe3sZuBQw1aBc5MyndvodzQlyqCZ7x1QPDHaWP4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 h1:Wgjft9X4W5pMeuqgPCHIQtbZ87wsgom7S5F8obreg+c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 h1:WWZA/I2K4ptBS1kg0kV1JbBtG/umed0vwHRrmcr9z7k= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0/go.mod h1:FWNzS4+zcWAP05IF7TDYTY1ysZAzIvogxWaDT9p8fsA= -github.com/aws/aws-sdk-go-v2/service/kms v1.24.1 h1:zDmx9yZjSYDaeakQVN16qfsLxhBeAxgclioB0+rOCDM= -github.com/aws/aws-sdk-go-v2/service/kms v1.24.1/go.mod h1:yrlimpsAJc9fXj3jHC7Ig2Zb4iMAoSJ/VVzChf22dZk= -github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1 h1:mTgFVlfQT8gikc5+/HwD8UL9jnUro5MGv8n/VEYF12I= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 h1:v0jkRigbSD6uOdwcaUQmgEwG1BkPfAPDqaeNt/29ghg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4/go.mod h1:LhTyt8J04LL+9cIt7pYJ5lbS/U98ZmXovLOR/4LUsk8= +github.com/aws/aws-sdk-go-v2/service/kms v1.24.7 h1:uRGw0UKo5hc7M2T7uGsK/Yg2qwecq/dnVjQbbq9RCzY= +github.com/aws/aws-sdk-go-v2/service/kms v1.24.7/go.mod h1:z3O9CXfVrKAV3c9fMWOUUv2C6N2ggXCDHeXpOB6lAEk= github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1/go.mod h1:6SOWLiobcZZshbmECRTADIRYliPL0etqFSigauQEeT0= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.13/go.mod h1:d7ptRksDDgvXaUvxyHZ9SYh+iMDymm94JbVcgvSYSzU= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 h1:DSNpSbfEgFXRV+IfEcKE5kTbqxm+MeF5WgyeRlsLnHY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0 h1:wl5dxN1NONhTDQD9uaEvNsDRX29cBmGED/nl0jkWlt4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0/go.mod h1:rDGMZA7f4pbmTtPOk5v5UM2lmX6UAbRnMDJeDvnH7AM= github.com/aws/aws-sdk-go-v2/service/sso v1.13.1/go.mod h1:TC9BubuFMVScIU+TLKamO6VZiYTkYoEHqlSQwAe2omw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 h1:hd0SKLMdOL/Sl6Z0np1PX9LeH2gqNtBe0MhTedA8MGI= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1/go.mod h1:XO/VcyoQ8nKyKfFW/3DMsRQXsfh/052tHTWmg3xBXRg= -github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 h1:pAOJj+80tC8sPVgSDHzMYD6KLWsaLQ1kZw31PTeORbs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 h1:HFiiRkf1SdaAmV3/BHOFZ9DjFynPHj8G/UIO1lQS+fk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= github.com/aws/aws-sdk-go-v2/service/sts v1.21.1/go.mod h1:G8SbvL0rFk4WOJroU8tKBczhsbhj2p/YY7qeJezJ3CI= -github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.12.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwFYTCZVhlsSSBvlbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220802171026-617dc7abb2ea h1:iWMTuQdgBQj66IRzxSuxPIrCuxvI2MK3co+E3bdmNys= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220802171026-617dc7abb2ea/go.mod h1:nIK6sJEuVZZUoMkOm3A8uU4UD82DDMJLu7pp1AtbyXs= +github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= +github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -291,8 +292,8 @@ github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7a github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4= github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= -github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= -github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -305,14 +306,15 @@ github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZ github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c= github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= -github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 h1:9Qh4lJ/KMr5iS1zfZ8I97+3MDpiKjl+0lZVUNBhdvRs= -github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08/go.mod h1:MAuu1uDJNOS3T3ui0qmKdPUwm59+bO19BbTph2wZafE= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.5 h1:g+wWynZqVALYAlpSQFAa7TscDnUK8mKYtrxMpw6AUKo= +github.com/cloudflare/circl v1.3.5/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -320,14 +322,13 @@ github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvA github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daixiang0/gci v0.11.2 h1:Oji+oPsp3bQ6bNNgX30NBAVT18P4uBH4sRZnlOlTj7Y= github.com/daixiang0/gci v0.11.2/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= -github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -351,16 +352,17 @@ github.com/disgoorg/log v1.2.1/go.mod h1:hhQWYTFTnIGzAuFPZyXJEi11IBm9wq+/TVZt/FE github.com/disgoorg/snowflake/v2 v2.0.1 h1:CuUxGLwggUxEswZOmZ+mZ5i0xSumQdXW9tXW7uGqe+0= github.com/disgoorg/snowflake/v2 v2.0.1/go.mod h1:SPU9c2CNn5DSyb86QcKtdZgix9osEtKrHLW4rMhfLCs= github.com/distribution/distribution/v3 v3.0.0-20221021092657-c47a966fded8 h1:zuxvqNfQKyGNH3a1yFh1ofD4Y7ycgdwQhHX6QRH+Cwo= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM= -github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= +github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= @@ -385,9 +387,6 @@ github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= -github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= -github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= @@ -397,8 +396,8 @@ github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIg github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghostiam/protogetter v0.2.3 h1:qdv2pzo3BpLqezwqfGDLZ+nHEYmc5bUpIdsMbBVwMjw= @@ -423,20 +422,21 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= +github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -525,6 +525,8 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -597,6 +599,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= @@ -626,8 +629,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ= -github.com/google/pprof v0.0.0-20230406165453-00490a63f317/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.5.0 h1:L16KZ3QvkFGpYhmp23iQip+mx1X39foEsqszjMNBm8A= github.com/google/rpmpack v0.5.0/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI= @@ -639,12 +642,12 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -685,19 +688,17 @@ github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrj github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= -github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc= -github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvznI6M3KdHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -728,7 +729,7 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4= +github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -756,8 +757,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkHAIKE/contextcheck v1.1.4 h1:B6zAaLhOEEcjvUgIYEqystmnFk1Oemn8bvJhbt0GMb8= github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -786,8 +787,8 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= -github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL43g16EQkPV/i8+b3l5bYQwLeoSBe7tS8= -github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA= +github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 h1:WGrKdjHtWC67RX96eTkYD2f53NDHhrq/7robWTAfk4s= +github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491/go.mod h1:o158RFmdEbYyIZmXAbrvmJWesbyxlLKee6X64VPVuOc= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= @@ -825,8 +826,8 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mgechev/revive v1.3.4 h1:k/tO3XTaWY4DEHal9tWBkkUMJYO/dLDVyMmAQxmIMDc= @@ -933,27 +934,27 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quasilyte/go-ruleguard v0.4.0 h1:DyM6r+TKL+xbKB4Nm7Afd1IQh9kEUKQs2pboWGKtvQo= github.com/quasilyte/go-ruleguard v0.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= @@ -988,6 +989,8 @@ github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tM github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.24.0 h1:MKNzmXtGh5N0y74Z/CIaJh4GlB364l0K1RUT08WSWAc= github.com/sashamelentyev/usestdlibvars v1.24.0/go.mod h1:9cYkq+gYJ+a5W2RPdhfaSCnTVUC1OQP/bSiiBhq3OZE= +github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg= +github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI= github.com/securego/gosec/v2 v2.18.2 h1:DkDt3wCiOtAHf1XkiXZBhQ6m6mK/b9T/wD257R3/c+I= github.com/securego/gosec/v2 v2.18.2/go.mod h1:xUuqSF6i0So56Y2wwohWAmB07EdBkUN6crbLlHwbyJs= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -998,19 +1001,18 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/sigstore/cosign/v2 v2.1.1 h1:HOI6pWaEie0wLituDWWaqC5U9MaXablKNf6QroVhj6k= -github.com/sigstore/cosign/v2 v2.1.1/go.mod h1:S9KGmdQ/Dd29TdgUwGCNeXR7scJWZwREh4A9Za2PRPY= -github.com/sigstore/rekor v1.2.2-0.20230530122220-67cc9e58bd23 h1:eZY7mQFcc0VvNr0fiAK3/n7kh73+T06KzBEIUYzFSDQ= -github.com/sigstore/rekor v1.2.2-0.20230530122220-67cc9e58bd23/go.mod h1:h1tOLhldpfILtziWpUDgGBu0vulWk9Kh72t6XzBGJok= -github.com/sigstore/sigstore v1.7.1 h1:fCATemikcBK0cG4+NcM940MfoIgmioY1vC6E66hXxks= -github.com/sigstore/sigstore v1.7.1/go.mod h1:0PmMzfJP2Y9+lugD0wer4e7TihR5tM7NcIs3bQNk5xg= +github.com/sigstore/cosign/v2 v2.2.1 h1:HauwPOMYYaVdQsnvUbF0P+ZsVPrkTB0G7Eq65+z1bQc= +github.com/sigstore/cosign/v2 v2.2.1/go.mod h1:4l1hELKWoFYzZ/p7+umrK6dhdBoBW0JbQRCIjOZIM9g= +github.com/sigstore/rekor v1.3.3 h1:pLZ0UjutL7SUdeiysmJCabnRqvI7DsIxnJj8c/+e0Fk= +github.com/sigstore/rekor v1.3.3/go.mod h1:GO3udo2Xiu3/Uz4/U3vgjVq7w5Yq7eSpAFP1z7gE+yA= +github.com/sigstore/sigstore v1.7.5 h1:ij55dBhLwjICmLTBJZm7SqoQLdsu/oowDanACcJNs48= +github.com/sigstore/sigstore v1.7.5/go.mod h1:9OCmYWhzuq/G4e1cy9m297tuMRJ1LExyrXY3ZC3Zt/s= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= @@ -1038,8 +1040,8 @@ github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1081,10 +1083,7 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= github.com/tetafro/godot v1.4.15 h1:QzdIs+XB8q+U1WmQEWKHQbKmCw06QuQM7gLx/dky2RM= github.com/tetafro/godot v1.4.15/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= -github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA= -github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= @@ -1103,24 +1102,23 @@ github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81v github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI= github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k= -github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= -github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38VVdoroRsT0Z88fmvdYrI2EjzJst35I= github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k= -github.com/xanzy/go-gitlab v0.90.0 h1:j8ZUHfLfXdnC+B8njeNaW/kM44c1zw8fiuNj7D+qQN8= -github.com/xanzy/go-gitlab v0.90.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= +github.com/xanzy/go-gitlab v0.93.2 h1:kNNf3BYNYn/Zkig0B89fma12l36VLcYSGu7OnaRlRDg= +github.com/xanzy/go-gitlab v0.93.2/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= @@ -1151,8 +1149,8 @@ go-simpler.org/sloglint v0.1.2/go.mod h1:2LL+QImPfTslD5muNPydAEYmpXIj6o/WYcqnJjL go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= +go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1163,17 +1161,15 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.tmz.dev/musttag v0.7.2 h1:1J6S9ipDbalBSODNT5jCep8dhZyMr4ttnjQagmGYR5s= go.tmz.dev/musttag v0.7.2/go.mod h1:m6q5NiiSKMnQYokefa2xGoyoXnrswCbJ0AWYzf4Zs28= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -gocloud.dev v0.33.0 h1:ET5z49jm1+eUhY5BkuGk2d7czfgGeXKd4vtg1Jcg9OQ= -gocloud.dev v0.33.0/go.mod h1:z6W8qorjrfM09H8t1MDk8KLPj3Xi26aFBzDKAHWIgLU= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +gocloud.dev v0.34.0 h1:LzlQY+4l2cMtuNfwT2ht4+fiXwWf/NmPTnXUlLmGif4= +gocloud.dev v0.34.0/go.mod h1:psKOachbnvY3DAOPbsFVmLIErwsbWPUG2H5i65D38vE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -1204,8 +1200,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 h1:jWGQJV4niP+CCmFW9ekjA9Zx8vYORzOUH2/Nl5WPuLQ= @@ -1303,8 +1299,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1319,8 +1315,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1387,8 +1383,6 @@ golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1415,6 +1409,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -1509,8 +1504,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1530,16 +1525,17 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA= -google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk= +google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1576,12 +1572,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1598,8 +1594,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1617,7 +1613,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= -gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1627,12 +1622,12 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-jose/go-jose.v2 v2.6.1 h1:qEzJlIDmG9q5VO0M/o8tGS65QMHMS1w01TQJB1VPJ4U= +gopkg.in/go-jose/go-jose.v2 v2.6.1/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= @@ -1663,12 +1658,12 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8= honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= +k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= @@ -1682,5 +1677,6 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= From a4ee3147a6f50bb65967343a79f7d4ce6a8e3702 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Mon, 13 Nov 2023 15:12:29 -0800 Subject: [PATCH 03/51] :seedling: bump project minimum Go version to go1.21 (#3661) * upgrade go.mod to 1.21 Signed-off-by: Spencer Schrock * use slices from stdlib Signed-off-by: Spencer Schrock * use max/min builtins Signed-off-by: Spencer Schrock * multierrors possibly spin this off into its own PR Signed-off-by: Spencer Schrock * dont call rand.Seed As of Go 1.20, the generator is seeded randomly at startup. https://pkg.go.dev/math/rand#Seed Signed-off-by: Spencer Schrock * update minimum Go version in documentation Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- .golangci.yml | 4 --- CONTRIBUTING.md | 2 +- checker/check_result.go | 4 +-- checks/evaluation/code_review.go | 3 +- checks/raw/shell_download_validate.go | 2 +- clients/githubrepo/branches.go | 2 +- clients/githubrepo/tarball.go | 8 ++--- clients/gitlabrepo/tarball.go | 14 ++++----- cmd/internal/nuget/client.go | 3 +- cmd/internal/nuget/client_test.go | 2 +- cmd/internal/scdiff/app/stats.go | 2 +- cron/data/blob.go | 2 +- cron/internal/shuffle/main.go | 2 -- finding/probe/probe.go | 4 +-- go.mod | 4 +-- go.sum | 43 +++++++++++++++++++++++++++ pkg/sarif.go | 13 ++------ rule/rule.go | 12 ++++---- 18 files changed, 77 insertions(+), 49 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f74587f3ff9..d926e3df145 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -80,10 +80,6 @@ linters-settings: errcheck: check-type-assertions: true check-blank: true - errorlint: - # TODO remove this when project migrates to golang 1.20 - # https://golangci-lint.run/usage/linters/#errorlint - errorf-multi: false exhaustive: # https://golangci-lint.run/usage/linters/#exhaustive default-signifies-exhaustive: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d8012f0a48c..c86a1586afe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,7 +43,7 @@ You must install these tools: 1. [`git`](https://help.github.com/articles/set-up-git/): For source control 1. [`go`](https://golang.org/doc/install): You need go version - [v1.19](https://golang.org/dl/) or higher. + [v1.21](https://golang.org/dl/) or higher. 1. [`docker`](https://docs.docker.com/engine/install/): `v18.9` or higher. diff --git a/checker/check_result.go b/checker/check_result.go index 00fc9172da1..7c3d601e426 100644 --- a/checker/check_result.go +++ b/checker/check_result.go @@ -107,7 +107,7 @@ func CreateProportionalScore(success, total int) int { return 0 } - return int(math.Min(float64(MaxResultScore*success/total), float64(MaxResultScore))) + return min(MaxResultScore*success/total, MaxResultScore) } // CreateProportionalScoreWeighted creates the proportional score @@ -141,7 +141,7 @@ func CreateProportionalScoreWeighted(scores ...ProportionalScoreWeighted) (int, return MaxResultScore, nil } - return int(math.Min(float64(MaxResultScore*ws/wt), float64(MaxResultScore))), nil + return min(MaxResultScore*ws/wt, MaxResultScore), nil } // AggregateScores adds up all scores diff --git a/checks/evaluation/code_review.go b/checks/evaluation/code_review.go index 4c84c92378b..edd59ded537 100644 --- a/checks/evaluation/code_review.go +++ b/checks/evaluation/code_review.go @@ -16,7 +16,6 @@ package evaluation import ( "fmt" - "math" "github.com/ossf/scorecard/v4/checker" sce "github.com/ossf/scorecard/v4/errors" @@ -74,7 +73,7 @@ func CodeReview(name string, dl checker.DetailLogger, r *checker.CodeReviewData) return checker.CreateProportionalScoreResult( name, fmt.Sprintf("found %d unreviewed changesets out of %d", nUnreviewedChanges, nChanges), - int(math.Max(float64(nChanges-nUnreviewedChanges), 0)), + max(nChanges-nUnreviewedChanges, 0), nChanges, ) } diff --git a/checks/raw/shell_download_validate.go b/checks/raw/shell_download_validate.go index d8aa1699f8f..19424b45c65 100644 --- a/checks/raw/shell_download_validate.go +++ b/checks/raw/shell_download_validate.go @@ -23,9 +23,9 @@ import ( "path" "path/filepath" "regexp" + "slices" "strings" - "golang.org/x/exp/slices" "mvdan.cc/sh/v3/syntax" "github.com/ossf/scorecard/v4/checker" diff --git a/clients/githubrepo/branches.go b/clients/githubrepo/branches.go index 3ddfac7054d..115c21964b6 100644 --- a/clients/githubrepo/branches.go +++ b/clients/githubrepo/branches.go @@ -17,12 +17,12 @@ package githubrepo import ( "context" "fmt" + "slices" "strings" "sync" "github.com/google/go-github/v53/github" "github.com/shurcooL/githubv4" - "golang.org/x/exp/slices" "github.com/ossf/scorecard/v4/clients" "github.com/ossf/scorecard/v4/clients/githubrepo/internal/fnmatch" diff --git a/clients/githubrepo/tarball.go b/clients/githubrepo/tarball.go index 3b3978e0a3d..3ba40fdfe83 100644 --- a/clients/githubrepo/tarball.go +++ b/clients/githubrepo/tarball.go @@ -153,7 +153,7 @@ func (handler *tarballHandler) getTarball() error { defer repoFile.Close() if _, err := io.Copy(repoFile, resp.Body); err != nil { // This can happen if the incoming tarball is corrupted/server gateway times out. - return fmt.Errorf("%w io.Copy: %v", errTarballNotFound, err) + return fmt.Errorf("%w io.Copy: %w", errTarballNotFound, err) } handler.tempDir = tempDir @@ -169,7 +169,7 @@ func (handler *tarballHandler) extractTarball() error { } gz, err := gzip.NewReader(in) if err != nil { - return fmt.Errorf("%w: gzip.NewReader %v %v", errTarballCorrupted, handler.tempTarFile, err) + return fmt.Errorf("%w: gzip.NewReader %v %w", errTarballCorrupted, handler.tempTarFile, err) } tr := tar.NewReader(gz) for { @@ -178,7 +178,7 @@ func (handler *tarballHandler) extractTarball() error { break } if err != nil { - return fmt.Errorf("%w tarReader.Next: %v", errTarballCorrupted, err) + return fmt.Errorf("%w tarReader.Next: %w", errTarballCorrupted, err) } switch header.Typeflag { @@ -217,7 +217,7 @@ func (handler *tarballHandler) extractTarball() error { // Potential for DoS vulnerability via decompression bomb. // Since such an attack will only impact a single shard, ignoring this for now. if _, err := io.Copy(outFile, tr); err != nil { - return fmt.Errorf("%w io.Copy: %v", errTarballCorrupted, err) + return fmt.Errorf("%w io.Copy: %w", errTarballCorrupted, err) } outFile.Close() handler.files = append(handler.files, diff --git a/clients/gitlabrepo/tarball.go b/clients/gitlabrepo/tarball.go index e8ff3be3bd4..61b48a69fe1 100644 --- a/clients/gitlabrepo/tarball.go +++ b/clients/gitlabrepo/tarball.go @@ -130,7 +130,7 @@ func (handler *tarballHandler) getTarball() error { } repoFile, err := os.CreateTemp(tempDir, repoFilename) if err != nil { - return fmt.Errorf("%w io.Copy: %v", errTarballNotFound, err) + return fmt.Errorf("%w io.Copy: %w", errTarballNotFound, err) } defer repoFile.Close() err = handler.apiFunction(url, tempDir, repoFile) @@ -188,18 +188,18 @@ func (handler *tarballHandler) apiFunction(url, tempDir string, repoFile *os.Fil req.Header.Set("PRIVATE-TOKEN", os.Getenv("GITLAB_AUTH_TOKEN")) resp, err := http.DefaultClient.Do(req) if err != nil { - return fmt.Errorf("%w io.Copy: %v", errTarballNotFound, err) + return fmt.Errorf("%w io.Copy: %w", errTarballNotFound, err) } defer resp.Body.Close() // Handler 400/404 errors. switch resp.StatusCode { case http.StatusNotFound, http.StatusBadRequest: - return fmt.Errorf("%w io.Copy: %v", errTarballNotFound, err) + return fmt.Errorf("%w io.Copy: %w", errTarballNotFound, err) } if _, err := io.Copy(repoFile, resp.Body); err != nil { // If the incoming tarball is corrupted or the server times out. - return fmt.Errorf("%w io.Copy: %v", errTarballNotFound, err) + return fmt.Errorf("%w io.Copy: %w", errTarballNotFound, err) } return nil } @@ -212,7 +212,7 @@ func (handler *tarballHandler) extractTarball() error { } gz, err := gzip.NewReader(in) if err != nil { - return fmt.Errorf("%w: gzip.NewReader %v %v", errTarballCorrupted, handler.tempTarFile, err) + return fmt.Errorf("%w: gzip.NewReader %v %w", errTarballCorrupted, handler.tempTarFile, err) } tr := tar.NewReader(gz) for { @@ -221,7 +221,7 @@ func (handler *tarballHandler) extractTarball() error { break } if err != nil { - return fmt.Errorf("%w tarReader.Next: %v", errTarballCorrupted, err) + return fmt.Errorf("%w tarReader.Next: %w", errTarballCorrupted, err) } switch header.Typeflag { @@ -260,7 +260,7 @@ func (handler *tarballHandler) extractTarball() error { // Potential for DoS vulnerability via decompression bomb. // Since such an attack will only impact a single shard, ignoring this for now. if _, err := io.Copy(outFile, tr); err != nil { - return fmt.Errorf("%w io.Copy: %v", errTarballCorrupted, err) + return fmt.Errorf("%w io.Copy: %w", errTarballCorrupted, err) } outFile.Close() handler.files = append(handler.files, diff --git a/cmd/internal/nuget/client.go b/cmd/internal/nuget/client.go index deb3d863e40..20b6682522a 100644 --- a/cmd/internal/nuget/client.go +++ b/cmd/internal/nuget/client.go @@ -22,10 +22,9 @@ import ( "io" "net/http" "regexp" + "slices" "strings" - "golang.org/x/exp/slices" - pmc "github.com/ossf/scorecard/v4/cmd/internal/packagemanager" sce "github.com/ossf/scorecard/v4/errors" ) diff --git a/cmd/internal/nuget/client_test.go b/cmd/internal/nuget/client_test.go index af48233ca36..5b25789f276 100644 --- a/cmd/internal/nuget/client_test.go +++ b/cmd/internal/nuget/client_test.go @@ -22,11 +22,11 @@ import ( "io" "net/http" "os" + "slices" "strings" "testing" "github.com/golang/mock/gomock" - "golang.org/x/exp/slices" pmc "github.com/ossf/scorecard/v4/cmd/internal/packagemanager" ) diff --git a/cmd/internal/scdiff/app/stats.go b/cmd/internal/scdiff/app/stats.go index d1a09eff6b8..704123d6eb3 100644 --- a/cmd/internal/scdiff/app/stats.go +++ b/cmd/internal/scdiff/app/stats.go @@ -20,11 +20,11 @@ import ( "fmt" "io" "os" + "slices" "strings" "text/tabwriter" "github.com/spf13/cobra" - "golang.org/x/exp/slices" "github.com/ossf/scorecard/v4/checker" "github.com/ossf/scorecard/v4/pkg" diff --git a/cron/data/blob.go b/cron/data/blob.go index 133030c4946..310374f6723 100644 --- a/cron/data/blob.go +++ b/cron/data/blob.go @@ -156,7 +156,7 @@ func ParseBlobFilename(key string) (time.Time, string, error) { objectName := key[len(filePrefixFormat):] t, err := time.Parse(filePrefixFormat, prefix) if err != nil { - return t, "", fmt.Errorf("%w: %v", errParseBlobName, err) + return t, "", fmt.Errorf("%w: %w", errParseBlobName, err) } return t, objectName, nil } diff --git a/cron/internal/shuffle/main.go b/cron/internal/shuffle/main.go index e04a10da6a0..9ffb5e8cc0e 100644 --- a/cron/internal/shuffle/main.go +++ b/cron/internal/shuffle/main.go @@ -19,7 +19,6 @@ import ( "math/rand" "os" "strconv" - "time" "github.com/ossf/scorecard/v4/cron/data" ) @@ -56,7 +55,6 @@ func main() { repoURLs = append(repoURLs, repo) } - rand.Seed(time.Now().UnixNano()) rand.Shuffle(len(repoURLs), func(i, j int) { repoURLs[i], repoURLs[j] = repoURLs[j], repoURLs[i] }) diff --git a/finding/probe/probe.go b/finding/probe/probe.go index 1db07e8e504..4e83a3a6a7a 100644 --- a/finding/probe/probe.go +++ b/finding/probe/probe.go @@ -141,7 +141,7 @@ func parseFromYAML(content []byte) (*yamlProbe, error) { err := yaml.Unmarshal(content, &r) if err != nil { - return nil, fmt.Errorf("%w: %v", errInvalid, err) + return nil, fmt.Errorf("%w: %w", errInvalid, err) } return &r, nil } @@ -151,7 +151,7 @@ func parseFromYAML(content []byte) (*yamlProbe, error) { func (r *RemediationEffort) UnmarshalYAML(n *yaml.Node) error { var str string if err := n.Decode(&str); err != nil { - return fmt.Errorf("%w: %v", errInvalid, err) + return fmt.Errorf("%w: %w", errInvalid, err) } // nolint:goconst diff --git a/go.mod b/go.mod index 8b462b9ecc1..0120a3f663f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ossf/scorecard/v4 -go 1.19 +go 1.21 require ( cloud.google.com/go/bigquery v1.57.1 @@ -174,7 +174,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.13.0 golang.org/x/sync v0.4.0 // indirect diff --git a/go.sum b/go.sum index caea459bdc9..8ecfea5dcc7 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,7 @@ cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2Aawl cloud.google.com/go/containeranalysis v0.11.1 h1:PHh4KTcMpCjYgxfV+TzvP24wolTGP9lGbqh9sBNHxjs= cloud.google.com/go/containeranalysis v0.11.1/go.mod h1:rYlUOM7nem1OJMKwE1SadufX0JP3wnXj844EtZAwWLY= cloud.google.com/go/datacatalog v1.18.1 h1:xJp9mZrc2HPaoxIz3sP9pCmf/impifweQ/yGG9VBfio= +cloud.google.com/go/datacatalog v1.18.1/go.mod h1:TzAWaz+ON1tkNr4MOcak8EBHX7wIRX/gZKM+yTVsv+A= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -31,6 +32,7 @@ cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQy cloud.google.com/go/kms v1.15.3 h1:RYsbxTRmk91ydKCzekI2YjryO4c5Y2M80Zwcs9/D/cI= cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ= cloud.google.com/go/longrunning v0.5.2 h1:u+oFqfEwwU7F9dIELigxbe0XVnBAo9wqMuQLA50CZ5k= +cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= cloud.google.com/go/monitoring v1.16.1 h1:CTklIuUkS5nCricGojPwdkSgPsCTX2HmYTxFDg+UvpU= cloud.google.com/go/monitoring v1.16.1/go.mod h1:6HsxddR+3y9j+o/cMJH6q/KJ/CBTvM/38L/1m7bTRJ4= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -85,6 +87,7 @@ github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBId github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= @@ -109,6 +112,7 @@ github.com/anchore/go-struct-converter v0.0.0-20230627203149-c72ef8859ca9/go.mod github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc= github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= @@ -120,29 +124,49 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.28.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.44.314 h1:d/5Jyk/Fb+PBd/4nzQg0JuC2W4A0knrDIzBgK/ggAow= github.com/aws/aws-sdk-go v1.44.314/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8= +github.com/aws/aws-sdk-go-v2 v1.20.0/go.mod h1:uWOr0m0jDsiWw8nnXiqZ+YG6LdvAlGYDLLf2NmHZoy4= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 h1:/MS8AzqYNAhhRNalOmxUvYs8VEbNGifTnzhPFdcRQkQ= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11/go.mod h1:va22++AdXht4ccO3kH2SHkHHYvZ2G9Utz+CXKmm2CaU= github.com/aws/aws-sdk-go-v2/config v1.18.32 h1:tqEOvkbTxwEV7hToRcJ1xZRjcATqwDVsWbAscgRKyNI= +github.com/aws/aws-sdk-go-v2/config v1.18.32/go.mod h1:U3ZF0fQRRA4gnbn9GGvOWLoT2EzzZfAWeKwnVrm1rDc= github.com/aws/aws-sdk-go-v2/credentials v1.13.31 h1:vJyON3lG7R8VOErpJJBclBADiWTwzcwdkQpTKx8D2sk= +github.com/aws/aws-sdk-go-v2/credentials v1.13.31/go.mod h1:T4sESjBtY2lNxLgkIASmeP57b5j7hTQqCbqG0tWnxC4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 h1:X3H6+SU21x+76LRglk21dFRgMTJMa5QcpW+SqUf5BBg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7/go.mod h1:3we0V09SwcJBzNlnyovrR2wWJhWmVdqAsmVs4uronv8= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76 h1:DJ1kHj0GI9BbX+XhF0kHxlzOVjcncmDUXmCvXdbfdAE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76/go.mod h1:/AZCdswMSgwpB2yMSFfY5H4pVeBLnCuPehdmO/r3xSM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 h1:zr/gxAZkMcvP71ZhQOcvdm8ReLjFgIXnIn0fw5AM7mo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37/go.mod h1:Pdn4j43v49Kk6+82spO3Tu5gSeQXRsxo56ePPQAvFiA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 h1:0HCMIkAkVY9KMgueD8tf4bRTUanzEYvhw7KkPXIMpO0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31/go.mod h1:fTJDMe8LOFYtqiFFFeHA+SVMAwqLhoq0kcInYoLa9Js= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 h1:+i1DOFrW3YZ3apE45tCal9+aDKK6kNEbW6Ib7e1nFxE= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38/go.mod h1:1/jLp0OgOaWIetycOmycW+vYTYgTZFPttJQRgsI1PoU= github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 h1:U5yySdwt2HPo/pnQec04DImLzWORbeWML1fJiLkKruI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0/go.mod h1:EhC/83j8/hL/UB1WmExo3gkElaja/KlmZM/gl1rTfjM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 h1:uAiiHnWihGP2rVp64fHwzLDrswGjEjsPszwRYMiYQPU= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12/go.mod h1:fUTHpOXqRQpXvEpDPSa3zxCc2fnpW6YnBoba+eQr+Bg= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 h1:kvN1jPHr9UffqqG3bSgZ8tx4+1zKVHz/Ktw/BwW6hX8= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32/go.mod h1:QmMEM7es84EUkbYWcpnkx8i5EW2uERPfrTFeOch128Y= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 h1:auGDJ0aLZahF5SPvkJ6WcUuX7iQ7kyl2MamV7Tm8QBk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31/go.mod h1:3+lloe3sZuBQw1aBc5MyndvodzQlyqCZ7x1QPDHaWP4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 h1:Wgjft9X4W5pMeuqgPCHIQtbZ87wsgom7S5F8obreg+c= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0/go.mod h1:FWNzS4+zcWAP05IF7TDYTY1ysZAzIvogxWaDT9p8fsA= github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1 h1:mTgFVlfQT8gikc5+/HwD8UL9jnUro5MGv8n/VEYF12I= +github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1/go.mod h1:6SOWLiobcZZshbmECRTADIRYliPL0etqFSigauQEeT0= github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 h1:DSNpSbfEgFXRV+IfEcKE5kTbqxm+MeF5WgyeRlsLnHY= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.1/go.mod h1:TC9BubuFMVScIU+TLKamO6VZiYTkYoEHqlSQwAe2omw= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 h1:hd0SKLMdOL/Sl6Z0np1PX9LeH2gqNtBe0MhTedA8MGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1/go.mod h1:XO/VcyoQ8nKyKfFW/3DMsRQXsfh/052tHTWmg3xBXRg= github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 h1:pAOJj+80tC8sPVgSDHzMYD6KLWsaLQ1kZw31PTeORbs= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.1/go.mod h1:G8SbvL0rFk4WOJroU8tKBczhsbhj2p/YY7qeJezJ3CI= github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io= +github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -153,6 +177,7 @@ github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2 github.com/bradleyfalzon/ghinstallation/v2 v2.8.0 h1:yUmoVv70H3J4UOqxqsee39+KlXxNEDfTbAp8c/qULKk= github.com/bradleyfalzon/ghinstallation/v2 v2.8.0/go.mod h1:fmPmvCiBWhJla3zDv9ZTQSZc8AbwyRnGW1yg5ep1Pcs= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/caarlos0/env/v6 v6.10.0 h1:lA7sxiGArZ2KkiqpOQNf8ERBRWI+v8MWIH+eGjSN22I= @@ -226,6 +251,7 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:Htrtb github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= @@ -241,22 +267,26 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.10.0 h1:F0x3xXrAWmhwtzoCokU4IMPcBdncG+HAAqi9FcOOjbQ= github.com/go-git/go-git/v5 v5.10.0/go.mod h1:1FOZ/pQnqw24ghP2n7cunVl0ON55BsjPYvhWHvZGhoo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -375,7 +405,9 @@ github.com/google/go-github/v56 v56.0.0/go.mod h1:D8cdcX98YWJvi7TLo7zM4/h8ZTx6u6 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= +github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -384,6 +416,7 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/osv-scanner v1.4.3 h1:V+vIjrC+HsDSzq8vWok/prjXl3Xg6i8u7gpejEIkcME= github.com/google/osv-scanner v1.4.3/go.mod h1:e2jwYUxCBQxlXlcMP7FdlmNu5XlBKA4hEhVXDBZZSzA= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -438,6 +471,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= @@ -458,6 +492,7 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20231023195312-e2daf7ba7156 h1:XaXfcSUnkTV/iujizC1//N5IrJA1v6KQHwMDbsZesoM= @@ -515,6 +550,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -610,6 +646,7 @@ github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVn github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= +github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= github.com/owenrumney/go-sarif/v2 v2.3.0 h1:wP5yEpI53zr0v5cBmagXzLbHZp9Oylyo3AJDpfLBITs= github.com/owenrumney/go-sarif/v2 v2.3.0/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= @@ -630,6 +667,7 @@ github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdL github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -660,6 +698,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -731,6 +770,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= +github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -760,6 +800,7 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -1052,6 +1093,7 @@ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3j golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1176,6 +1218,7 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/sarif.go b/pkg/sarif.go index 30f43d01294..037907a274e 100644 --- a/pkg/sarif.go +++ b/pkg/sarif.go @@ -158,13 +158,6 @@ type sarif210 struct { Runs []run `json:"runs"` } -func maxOffset(x, y uint) uint { - if x < y { - return y - } - return x -} - func calculateSeverityLevel(risk string) string { //nolint:lll // https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#reportingdescriptor-object. @@ -273,7 +266,7 @@ func detailToRegion(details *checker.CheckDetail) region { default: panic("invalid") case finding.FileTypeURL: - line := maxOffset(checker.OffsetDefault, getStartLine(details)) + line := max(checker.OffsetDefault, getStartLine(details)) reg = region{ StartLine: &line, Snippet: snippet, @@ -281,8 +274,8 @@ func detailToRegion(details *checker.CheckDetail) region { case finding.FileTypeNone: // Do nothing. case finding.FileTypeSource: - startLine := maxOffset(checker.OffsetDefault, getStartLine(details)) - endLine := maxOffset(startLine, getEndLine(details)) + startLine := max(checker.OffsetDefault, getStartLine(details)) + endLine := max(startLine, getEndLine(details)) reg = region{ StartLine: &startLine, EndLine: &endLine, diff --git a/rule/rule.go b/rule/rule.go index 9168f851d71..1660392465c 100644 --- a/rule/rule.go +++ b/rule/rule.go @@ -98,7 +98,7 @@ var errInvalid = errors.New("invalid") func New(loc embed.FS, rule string) (*Rule, error) { content, err := loc.ReadFile(fmt.Sprintf("%s.yml", rule)) if err != nil { - return nil, fmt.Errorf("%w: %v", errInvalid, err) + return nil, fmt.Errorf("%w: %w", errInvalid, err) } r, err := parseFromJSON(content) @@ -126,10 +126,10 @@ func New(loc embed.FS, rule string) (*Rule, error) { func validate(r *jsonRule) error { if err := validateRisk(r.Risk); err != nil { - return fmt.Errorf("%w: %v", errInvalid, err) + return fmt.Errorf("%w: %w", errInvalid, err) } if err := validateRemediation(r.Remediation); err != nil { - return fmt.Errorf("%w: %v", errInvalid, err) + return fmt.Errorf("%w: %w", errInvalid, err) } return nil } @@ -157,7 +157,7 @@ func parseFromJSON(content []byte) (*jsonRule, error) { err := yaml.Unmarshal(content, &r) if err != nil { - return nil, fmt.Errorf("%w: %v", errInvalid, err) + return nil, fmt.Errorf("%w: %w", errInvalid, err) } return &r, nil } @@ -167,7 +167,7 @@ func parseFromJSON(content []byte) (*jsonRule, error) { func (r *RemediationEffort) UnmarshalYAML(n *yaml.Node) error { var str string if err := n.Decode(&str); err != nil { - return fmt.Errorf("%w: %v", errInvalid, err) + return fmt.Errorf("%w: %w", errInvalid, err) } // nolint:goconst @@ -189,7 +189,7 @@ func (r *RemediationEffort) UnmarshalYAML(n *yaml.Node) error { func (r *Risk) UnmarshalYAML(n *yaml.Node) error { var str string if err := n.Decode(&str); err != nil { - return fmt.Errorf("%w: %v", errInvalid, err) + return fmt.Errorf("%w: %w", errInvalid, err) } switch n.Value { From 14f864bfeae1703fe9cb3f343205ac44d8b283bc Mon Sep 17 00:00:00 2001 From: Allen Shearin Date: Tue, 14 Nov 2023 20:24:47 -0700 Subject: [PATCH 04/51] :sparkles: Add commit depth support for GitLab (#3672) * feat: Integrated paging to allow for querying based on the --commit-depth value provided Signed-off-by: Allen Shearin * fix: rework git commits changes for readability Signed-off-by: Allen Shearin * fix: add additional commit depth test Signed-off-by: Allen Shearin --------- Signed-off-by: Allen Shearin --- clients/gitlabrepo/client.go | 2 +- clients/gitlabrepo/commits.go | 55 ++- clients/gitlabrepo/commits_test.go | 81 ++++ clients/gitlabrepo/testdata/valid-commits | 514 ++++++++++++++++++++++ 4 files changed, 636 insertions(+), 16 deletions(-) create mode 100644 clients/gitlabrepo/testdata/valid-commits diff --git a/clients/gitlabrepo/client.go b/clients/gitlabrepo/client.go index a0196d245b1..17b417d358f 100644 --- a/clients/gitlabrepo/client.go +++ b/clients/gitlabrepo/client.go @@ -114,7 +114,7 @@ func (client *Client) InitRepo(inputRepo clients.Repo, commitSHA string, commitD client.contributors.init(client.repourl) // Init commitsHandler - client.commits.init(client.repourl) + client.commits.init(client.repourl, client.commitDepth) // Init branchesHandler client.branches.init(client.repourl) diff --git a/clients/gitlabrepo/commits.go b/clients/gitlabrepo/commits.go index 697cf86c503..826000fc3bf 100644 --- a/clients/gitlabrepo/commits.go +++ b/clients/gitlabrepo/commits.go @@ -27,31 +27,56 @@ import ( ) type commitsHandler struct { - glClient *gitlab.Client - once *sync.Once - errSetup error - repourl *repoURL - commitsRaw []*gitlab.Commit + glClient *gitlab.Client + once *sync.Once + errSetup error + repourl *repoURL + commitsRaw []*gitlab.Commit + commitDepth int } -func (handler *commitsHandler) init(repourl *repoURL) { +func (handler *commitsHandler) init(repourl *repoURL, commitDepth int) { handler.repourl = repourl handler.errSetup = nil handler.once = new(sync.Once) + handler.commitDepth = commitDepth } func (handler *commitsHandler) setup() error { handler.once.Do(func() { - commits, _, err := handler.glClient.Commits.ListCommits( - handler.repourl.projectID, - &gitlab.ListCommitsOptions{ - RefName: &handler.repourl.commitSHA, - }, - ) - if err != nil { - handler.errSetup = fmt.Errorf("request for commits failed with %w", err) - return + var commits []*gitlab.Commit + opt := gitlab.ListOptions{ + Page: 1, + PerPage: handler.commitDepth, } + + for { + c, resp, err := handler.glClient.Commits.ListCommits(handler.repourl.projectID, + &gitlab.ListCommitsOptions{ + RefName: &handler.repourl.commitSHA, + ListOptions: opt, + }) + if err != nil { + handler.errSetup = fmt.Errorf("request for commits failed with %w", err) + return + } + + commits = append(commits, c...) + + if len(commits) >= handler.commitDepth { + commits = commits[:handler.commitDepth] + break + } + + // Exit the loop when we've seen all pages. + if resp.NextPage == 0 { + break + } + + // Update the page number to get the next page. + opt.Page = resp.NextPage + } + handler.commitsRaw = commits if handler.repourl.commitSHA != clients.HeadSHA { //nolint:lll diff --git a/clients/gitlabrepo/commits_test.go b/clients/gitlabrepo/commits_test.go index d7bc6b96bd9..dfb3769f669 100644 --- a/clients/gitlabrepo/commits_test.go +++ b/clients/gitlabrepo/commits_test.go @@ -15,7 +15,13 @@ package gitlabrepo import ( + "net/http" "testing" + + "github.com/google/go-cmp/cmp" + "github.com/xanzy/go-gitlab" + + "github.com/ossf/scorecard/v4/clients" ) func TestParsingEmail(t *testing.T) { @@ -56,3 +62,78 @@ func TestParsingEmail(t *testing.T) { }) } } + +func TestListRawCommits(t *testing.T) { + t.Parallel() + tests := []struct { + name string + commitsPath string + commitDepth int + want int + wantErr bool + }{ + { + name: "commits to non-default depth", + commitsPath: "./testdata/valid-commits", + commitDepth: 17, + want: 17, + wantErr: false, + }, + { + name: "commits to default depth", + commitsPath: "./testdata/valid-commits", + commitDepth: 30, + want: 30, + wantErr: false, + }, + { + name: "request more commits than exist in the repo", + commitsPath: "./testdata/valid-commits", + commitDepth: 60, + want: 32, + wantErr: false, + }, + { + name: "failure fetching commits", + commitsPath: "./testdata/invalid-commits", + commitDepth: 30, + want: 0, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + httpClient := &http.Client{ + Transport: suffixStubTripper{ + responsePaths: map[string]string{ + "commits": tt.commitsPath, // corresponds to projects//repository/commits + }, + }, + } + client, err := gitlab.NewClient("", gitlab.WithHTTPClient(httpClient)) + if err != nil { + t.Fatalf("gitlab.NewClient error: %v", err) + } + handler := &commitsHandler{ + glClient: client, + } + + repoURL := repoURL{ + owner: "ossf-tests", + commitSHA: clients.HeadSHA, + } + + handler.init(&repoURL, tt.commitDepth) + commits, err := handler.listRawCommits() + if (err != nil) != tt.wantErr { + t.Fatalf("listIssues error: %v, wantedErr: %t", err, tt.wantErr) + } + if !cmp.Equal(len(commits), tt.want) { + t.Errorf("listCommits() = %v, want %v", len(commits), cmp.Diff(len(commits), tt.want)) + } + }) + } +} diff --git a/clients/gitlabrepo/testdata/valid-commits b/clients/gitlabrepo/testdata/valid-commits new file mode 100644 index 00000000000..99089839775 --- /dev/null +++ b/clients/gitlabrepo/testdata/valid-commits @@ -0,0 +1,514 @@ +[ + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Example User", + "author_email": "user@example.com", + "authored_date": "2021-09-20T11:50:22.001+00:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com", + "committed_date": "2021-09-20T11:50:22.001+00:00", + "created_at": "2021-09-20T11:50:22.001+00:00", + "message": "Replace sanitize with escape once", + "parent_ids": [ + "6104942438c14ec7bd21c6cd5bd995272b3faff6" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "user@example.com", + "committer_name": "ExampleName", + "committer_email": "user@example.com", + "created_at": "2021-09-20T09:06:12.201+00:00", + "message": "Sanitize for network graph", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" + } +] \ No newline at end of file From 8ac1b43feaf3d3032e7b3c06d29e80be2a5d43d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 13:04:04 -0500 Subject: [PATCH 05/51] :seedling: Bump github.com/xanzy/go-gitlab from 0.93.2 to 0.94.0 (#3674) Bumps [github.com/xanzy/go-gitlab](https://github.com/xanzy/go-gitlab) from 0.93.2 to 0.94.0. - [Changelog](https://github.com/xanzy/go-gitlab/blob/main/releases_test.go) - [Commits](https://github.com/xanzy/go-gitlab/compare/v0.93.2...v0.94.0) --- updated-dependencies: - dependency-name: github.com/xanzy/go-gitlab dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0120a3f663f..95f39e63153 100644 --- a/go.mod +++ b/go.mod @@ -169,7 +169,7 @@ require ( github.com/sergi/go-diff v1.3.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/vbatts/tar-split v0.11.3 // indirect - github.com/xanzy/go-gitlab v0.93.2 + github.com/xanzy/go-gitlab v0.94.0 github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/go.sum b/go.sum index 8ecfea5dcc7..27b45dcb66f 100644 --- a/go.sum +++ b/go.sum @@ -782,8 +782,8 @@ github.com/vdemeester/k8s-pkg-credentialprovider v1.18.1-0.20201019120933-f1d169 github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/xanzy/go-gitlab v0.93.2 h1:kNNf3BYNYn/Zkig0B89fma12l36VLcYSGu7OnaRlRDg= -github.com/xanzy/go-gitlab v0.93.2/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= +github.com/xanzy/go-gitlab v0.94.0 h1:GmBl2T5zqUHqyjkxFSvsT7CbelGdAH/dmBqUBqS+4BE= +github.com/xanzy/go-gitlab v0.94.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= From 6541b0d2fd80808703ced731ff567079e5d03fac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:16:06 +0000 Subject: [PATCH 06/51] :seedling: Bump github.com/onsi/ginkgo/v2 in /tools (#3668) Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.0...v2.13.1) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/go.mod | 4 ++-- tools/go.sum | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index 294395dabca..809feb74f0c 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -8,7 +8,7 @@ require ( github.com/google/addlicense v1.1.1 github.com/google/ko v0.15.0 github.com/goreleaser/goreleaser v1.20.0 - github.com/onsi/ginkgo/v2 v2.13.0 + github.com/onsi/ginkgo/v2 v2.13.1 google.golang.org/protobuf v1.31.0 ) @@ -370,7 +370,7 @@ require ( golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index 0d3e1011b11..8161892c094 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -889,13 +889,13 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= +github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= @@ -1389,8 +1389,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From ea626de8301e450c5ae120b0a799261c0cea213d Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Wed, 15 Nov 2023 10:35:27 -0800 Subject: [PATCH 07/51] :seedling: update CI-Tests e2e to reflect 30 commits (#3676) 14f864bfeae1703fe9cb3f343205ac44d8b283bc not only fixed the --commit-depth option, but also fixed the default commit depth for GitLab repos. Previously GitLab repos looked back 20 commits because that was GitLab's default for the commits API. Now, GitLab repos look back 30 commits, so the proportions of this e2e test changed. Signed-off-by: Spencer Schrock --- e2e/ci_tests_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/ci_tests_test.go b/e2e/ci_tests_test.go index 9730e4e432a..69c3699eb0e 100644 --- a/e2e/ci_tests_test.go +++ b/e2e/ci_tests_test.go @@ -121,13 +121,13 @@ var _ = Describe("E2E TEST:"+checks.CheckCITests, func() { } expected := scut.TestReturn{ Error: nil, - Score: 8, + Score: 6, NumberOfWarn: 0, NumberOfInfo: 0, - NumberOfDebug: 13, + NumberOfDebug: 22, } result := checks.CITests(&req) - Expect(result.Score).Should(BeNumerically("==", expected.Score)) + Expect(scut.ValidateTestReturn(nil, "CI tests at commit - GitLab", &expected, &result, &dl)).Should(BeTrue()) Expect(result.Error).Should(BeNil()) Expect(repoClient.Close()).Should(BeNil()) }) From 288319ad127a273dc4b3a259b0b17eb7d5c64286 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Wed, 15 Nov 2023 11:01:53 -0800 Subject: [PATCH 08/51] :seedling: scdiff: Add workflow to run `scdiff` against PRs on demand (#3640) * wip Signed-off-by: Spencer Schrock * try to use jq without quotes Signed-off-by: Spencer Schrock * try to make file another way. Signed-off-by: Spencer Schrock * try using homedir Signed-off-by: Spencer Schrock * add github token to env Signed-off-by: Spencer Schrock * add link to workflow run Signed-off-by: Spencer Schrock * make comment its own job Signed-off-by: Spencer Schrock * fix typo in job context Signed-off-by: Spencer Schrock * typo part 2 Signed-off-by: Spencer Schrock * use github-script to get PR SHAs. Signed-off-by: Spencer Schrock * need to go through one more type to get to API response. Signed-off-by: Spencer Schrock * temporarily use monitor action to see the required permissions Signed-off-by: Spencer Schrock * spacing is hard Signed-off-by: Spencer Schrock * remove monitor and apply minimal permissions the read-all at the top might be too broad, but the monitor doesnt support graphql so best we can do for now. Signed-off-by: Spencer Schrock * try to set the checks Signed-off-by: Spencer Schrock * read the comment body Signed-off-by: Spencer Schrock * try to get around regex syntax error? Signed-off-by: Spencer Schrock * quote comment body Signed-off-by: Spencer Schrock * we want to pass an empty string to the args Signed-off-by: Spencer Schrock * fix the regex string Signed-off-by: Spencer Schrock * rest of repo has upgraded Signed-off-by: Spencer Schrock * seed 15 repos to analyze to start with Signed-off-by: Spencer Schrock * support gitlab repos in scdiff Signed-off-by: Spencer Schrock * rename pr step to config we also need the checks to run, so update the name to reflect that Signed-off-by: Spencer Schrock * switch from default token to a PAT By default, the GitHub Action token gets 1000 req/hour. If running all checks, the before/after each take about 1100 of core quota A PAT grants 5000/hr so the 2200 required should be fine if used infrequently. Ideally, the caller will always pass the check they care about into the command Signed-off-by: Spencer Schrock * escape comment body with bash Signed-off-by: Spencer Schrock * setup go manually Signed-off-by: Spencer Schrock * don't need to run on comment delete Signed-off-by: Spencer Schrock * limit scdiff to individuals with repo access Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- .github/workflows/scdiff.yml | 115 ++++++++++++++++++ cmd/internal/scdiff/app/runner/runner.go | 21 +++- cmd/internal/scdiff/app/runner/runner_test.go | 2 +- 3 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/scdiff.yml diff --git a/.github/workflows/scdiff.yml b/.github/workflows/scdiff.yml new file mode 100644 index 00000000000..3dd02033d8a --- /dev/null +++ b/.github/workflows/scdiff.yml @@ -0,0 +1,115 @@ +name: scdiff PR evaluation +on: + issue_comment: + types: [created, edited] + +permissions: read-all + +env: + GO_VERSION: 1.21 + +jobs: + share-link: + if: ${{ (github.event.issue.pull_request) && (contains(github.event.comment.body, '/scdiff generate')) }} + runs-on: [ubuntu-latest] + permissions: + pull-requests: write # to create the PR comment + steps: + - name: share link to workflow run + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `[Here's a link to the scdiff run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` + }) + + golden-test: + if: ${{ (github.event.issue.pull_request) && (contains(github.event.comment.body, '/scdiff generate')) }} + runs-on: [ubuntu-latest] + steps: + - name: create file of repos to anlayze + run: | + cat < $HOME/repos.txt + https://github.com/airbnb/lottie-web + https://github.com/apache/tomcat + https://github.com/Azure/azure-functions-dotnet-worker + https://github.com/cncf/xds + https://github.com/google/go-cmp + https://github.com/google/highwayhash + https://github.com/googleapis/google-api-php-client + https://github.com/jacoco/jacoco + https://github.com/ossf/scorecard + https://github.com/pallets/jinja + https://github.com/polymer/polymer + https://github.com/rust-random/getrandom + https://github.com/yaml/libyaml + https://gitlab.com/baserow/baserow + https://gitlab.com/cryptsetup/cryptsetup + EOF + # use shell syntax to escape, since the checks arg goes to CLI when calling scdiff + - name: escape comment body + id: comment + env: + BODY: ${{ github.event.comment.body }} + run: | + echo "body=$BODY" >> $GITHUB_OUTPUT + - name: configure scdiff + id: config + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 + with: + script: | + const allowedAssociations = ["COLLABORATOR", "MEMBER", "OWNER"]; + authorAssociation = '${{ github.event.comment.author_association }}' + if (!allowedAssociations.includes(authorAssociation)) { + core.setFailed("You don't have access to run scdiff"); + } + + const response = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }) + core.setOutput('base', response.data.base.sha) + core.setOutput('head', response.data.head.sha) + + checks = '""' + const commentBody = '${{ steps.comment.outputs.body }}' + const regex = /\/scdiff generate ([^ ]+)/; + const found = commentBody.match(regex); + if (found && found.length == 2) { + checks = found[1] + } + core.setOutput('checks', checks) + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ steps.config.outputs.base }} + - name: Setup Go + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + with: + go-version: ${{ env.GO_VERSION }} + check-latest: true + - name: generate before results + env: + GITHUB_AUTH_TOKEN: ${{ secrets.GH_AUTH_TOKEN }} + GITLAB_AUTH_TOKEN: ${{ secrets.GITLAB_TOKEN }} + run: | + go run cmd/internal/scdiff/main.go generate \ + --repos $HOME/repos.txt \ + --checks ${{ steps.config.outputs.checks }} > $HOME/before.json + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ steps.config.outputs.head }} + - name: generate after results + env: + GITHUB_AUTH_TOKEN: ${{ secrets.GH_AUTH_TOKEN }} + GITLAB_AUTH_TOKEN: ${{ secrets.GITLAB_TOKEN }} + run: | + go run cmd/internal/scdiff/main.go generate \ + --repos $HOME/repos.txt \ + --checks ${{ steps.config.outputs.checks }} > $HOME/after.json + - name: compare results + run: | + go run cmd/internal/scdiff/main.go compare $HOME/before.json $HOME/after.json diff --git a/cmd/internal/scdiff/app/runner/runner.go b/cmd/internal/scdiff/app/runner/runner.go index 535bc7a84f2..85b345d3819 100644 --- a/cmd/internal/scdiff/app/runner/runner.go +++ b/cmd/internal/scdiff/app/runner/runner.go @@ -16,13 +16,16 @@ package runner import ( "context" + "errors" "strings" "github.com/ossf/scorecard/v4/checker" "github.com/ossf/scorecard/v4/checks" "github.com/ossf/scorecard/v4/clients" "github.com/ossf/scorecard/v4/clients/githubrepo" + "github.com/ossf/scorecard/v4/clients/gitlabrepo" "github.com/ossf/scorecard/v4/clients/ossfuzz" + sce "github.com/ossf/scorecard/v4/errors" "github.com/ossf/scorecard/v4/log" "github.com/ossf/scorecard/v4/pkg" ) @@ -37,7 +40,8 @@ type Runner struct { ctx context.Context logger *log.Logger enabledChecks checker.CheckNameToFnMap - repoClient clients.RepoClient + githubClient clients.RepoClient + gitlabClient clients.RepoClient ossFuzz clients.RepoClient cii clients.CIIBestPracticesClient vuln clients.VulnerabilitiesClient @@ -47,10 +51,15 @@ type Runner struct { func New(enabledChecks []string) Runner { ctx := context.Background() logger := log.NewLogger(log.DefaultLevel) + gitlabClient, err := gitlabrepo.CreateGitlabClient(ctx, "https://gitlab.com") + if err != nil { + logger.Error(err, "creating gitlab client") + } return Runner{ ctx: ctx, logger: logger, - repoClient: githubrepo.CreateGithubRepoClient(ctx, logger), + githubClient: githubrepo.CreateGithubRepoClient(ctx, logger), + gitlabClient: gitlabClient, ossFuzz: ossfuzz.CreateOSSFuzzClient(ossfuzz.StatusURL), cii: clients.DefaultCIIBestPracticesClient(), vuln: clients.DefaultVulnerabilitiesClient(), @@ -61,12 +70,16 @@ func New(enabledChecks []string) Runner { //nolint:wrapcheck func (r *Runner) Run(repoURI string) (pkg.ScorecardResult, error) { r.log("processing repo: " + repoURI) - // TODO (gitlab?) + repoClient := r.githubClient repo, err := githubrepo.MakeGithubRepo(repoURI) + if errors.Is(err, sce.ErrorUnsupportedHost) { + repo, err = gitlabrepo.MakeGitlabRepo(repoURI) + repoClient = r.gitlabClient + } if err != nil { return pkg.ScorecardResult{}, err } - return pkg.RunScorecard(r.ctx, repo, commit, commitDepth, r.enabledChecks, r.repoClient, r.ossFuzz, r.cii, r.vuln) + return pkg.RunScorecard(r.ctx, repo, commit, commitDepth, r.enabledChecks, repoClient, r.ossFuzz, r.cii, r.vuln) } // logs only if logger is set. diff --git a/cmd/internal/scdiff/app/runner/runner_test.go b/cmd/internal/scdiff/app/runner/runner_test.go index 1b4c05e3c4a..07bfb6135ff 100644 --- a/cmd/internal/scdiff/app/runner/runner_test.go +++ b/cmd/internal/scdiff/app/runner/runner_test.go @@ -46,7 +46,7 @@ func TestRunner_Run(t *testing.T) { mockRepo.EXPECT().Close().Return(nil) r := Runner{ enabledChecks: checker.CheckNameToFnMap{}, - repoClient: mockRepo, + githubClient: mockRepo, } const repo = "github.com/foo/bar" result, err := r.Run(repo) From 92470deac34ef9eaaa2707e13b7d800088e0898c Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Wed, 15 Nov 2023 11:44:28 -0800 Subject: [PATCH 09/51] :seedling: enable `nolintlint` linter and fix violations (#3650) * enable nolintlint Signed-off-by: Spencer Schrock * first chunk of fixing nolintlint Signed-off-by: Spencer Schrock * second chunk of fixing nolintlint Signed-off-by: Spencer Schrock * third chunk of fixing nolintlint Signed-off-by: Spencer Schrock * fourth chunk of fixing nolintlint Signed-off-by: Spencer Schrock * include reason for the specific linter config Signed-off-by: Spencer Schrock * fifth chunk of fixing nolintlint Signed-off-by: Spencer Schrock * fix linter errors that are somehow still triggering Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- .golangci.yml | 5 ++++ attestor/policy/attestation_policy_test.go | 4 +-- checker/check_result_test.go | 24 ++++++++--------- checker/client_test.go | 5 ++-- checker/raw_result.go | 4 +-- checks/all_checks_test.go | 4 +-- checks/branch_protection_test.go | 3 +-- checks/code_review_test.go | 3 +-- checks/contributors_test.go | 5 +--- checks/dependency_update_tool.go | 2 +- checks/dependency_update_tool_test.go | 2 +- checks/evaluation/binary_artifacts_test.go | 2 +- checks/evaluation/ci_tests_test.go | 18 ++++++------- .../evaluation/dependency_update_tool_test.go | 1 - checks/evaluation/pinned_dependencies_test.go | 4 +-- checks/evaluation/security_policy_test.go | 1 - checks/evaluation/signed_releases.go | 3 ++- checks/evaluation/vulnerabilities_test.go | 20 +++++++------- checks/evaluation/webhooks_test.go | 2 +- checks/fileparser/github_workflow_test.go | 10 +++---- checks/fileparser/listing_test.go | 10 +++---- checks/fuzzing_test.go | 6 ++--- checks/maintained_test.go | 9 +++---- checks/permissions_test.go | 2 +- checks/raw/branch_protection_test.go | 4 +-- checks/raw/dependency_update_tool_test.go | 2 +- checks/raw/fuzzing_test.go | 15 +++++------ checks/raw/gitlab/packaging_test.go | 8 +++--- checks/raw/license_test.go | 2 +- checks/raw/maintained_test.go | 8 +++--- checks/raw/permissions.go | 5 ++-- checks/raw/pinned_dependencies.go | 2 +- checks/raw/pinned_dependencies_test.go | 27 +++++++++---------- checks/raw/security_policy_test.go | 2 +- checks/raw/shell_download_validate.go | 1 - checks/raw/vulnerabilities_test.go | 6 ++--- checks/raw/webhooks_test.go | 2 +- checks/sast_test.go | 2 +- checks/security_policy_test.go | 2 +- checks/signed_releases_test.go | 7 +++-- checks/webhook_test.go | 2 +- clients/cii_http_client.go | 2 +- clients/git/client_test.go | 2 +- clients/githubrepo/checkruns.go | 2 +- clients/githubrepo/graphql.go | 3 +-- clients/githubrepo/repo_test.go | 3 +-- .../roundtripper/rate_limit_test.go | 9 ++++--- .../githubrepo/roundtripper/roundtripper.go | 9 ++++--- .../roundtripper/tokens/server/main.go | 4 +-- clients/githubrepo/tarball.go | 4 +-- clients/githubrepo/tarball_test.go | 2 +- clients/gitlabrepo/branches.go | 2 +- clients/gitlabrepo/branches_test.go | 4 +-- clients/gitlabrepo/contributors.go | 4 +-- clients/gitlabrepo/graphql.go | 2 -- clients/gitlabrepo/tarball.go | 4 +-- clients/gitlabrepo/tarball_test.go | 2 +- cmd/internal/nuget/client.go | 20 +++++++------- cmd/internal/nuget/client_test.go | 12 ++++----- cmd/internal/packagemanager/client.go | 6 ++--- cmd/internal/packagemanager/client_test.go | 8 ++---- cmd/package_managers_test.go | 25 +++++++---------- cmd/serve.go | 2 +- cron/config/config.go | 2 +- cron/config/config_test.go | 2 +- cron/data/summary.go | 2 +- cron/internal/bq/main.go | 2 +- cron/internal/controller/bucket_test.go | 3 +-- cron/internal/format/json_test.go | 4 +-- cron/internal/format/mock_doc.go | 3 +-- cron/internal/format/schema_gen_test.go | 4 +-- cron/internal/pubsub/publisher_test.go | 4 +-- cron/internal/pubsub/subscriber_gocloud.go | 1 - .../pubsub/subscriber_gocloud_test.go | 4 +-- cron/internal/webhook/main.go | 2 +- cron/internal/worker/main.go | 2 +- dependencydiff/dependencydiff_test.go | 7 ++--- dependencydiff/mapping.go | 3 +-- docs/checks/impl.go | 4 +-- docs/checks/internal/generate/main.go | 2 +- finding/finding.go | 8 +++--- finding/finding_test.go | 2 +- finding/probe/probe.go | 5 +--- finding/probe/probe_test.go | 2 +- options/options_test.go | 7 ++--- pkg/json.go | 3 +-- pkg/json_probe_results.go | 2 -- pkg/json_raw_results.go | 4 +-- pkg/json_test.go | 3 ++- pkg/mock_doc.go | 3 +-- pkg/sarif.go | 17 ++++++------ pkg/sarif_test.go | 10 +------ pkg/scorecard_result.go | 1 - policy/policy_test.go | 2 +- probes/contributorsFromOrgOrCompany/impl.go | 2 +- .../contributorsFromOrgOrCompany/impl_test.go | 4 +-- probes/fuzzedWithCLibFuzzer/impl.go | 2 +- probes/fuzzedWithCLibFuzzer/impl_test.go | 4 +-- probes/fuzzedWithClusterFuzzLite/impl.go | 2 +- probes/fuzzedWithClusterFuzzLite/impl_test.go | 4 +-- probes/fuzzedWithCppLibFuzzer/impl.go | 2 +- probes/fuzzedWithCppLibFuzzer/impl_test.go | 4 +-- probes/fuzzedWithGoNative/impl.go | 2 +- probes/fuzzedWithGoNative/impl_test.go | 4 +-- probes/fuzzedWithJavaJazzerFuzzer/impl.go | 2 +- .../fuzzedWithJavaJazzerFuzzer/impl_test.go | 4 +-- probes/fuzzedWithOSSFuzz/impl.go | 2 +- probes/fuzzedWithOSSFuzz/impl_test.go | 4 +-- probes/fuzzedWithPropertyBasedHaskell/impl.go | 2 +- .../impl_test.go | 4 +-- .../fuzzedWithPropertyBasedJavascript/impl.go | 2 +- .../impl_test.go | 4 +-- .../fuzzedWithPropertyBasedTypescript/impl.go | 2 +- .../impl_test.go | 4 +-- probes/fuzzedWithPythonAtheris/impl.go | 2 +- probes/fuzzedWithPythonAtheris/impl_test.go | 4 +-- probes/fuzzedWithRustCargofuzz/impl.go | 2 +- probes/fuzzedWithRustCargofuzz/impl_test.go | 4 +-- probes/fuzzedWithSwiftLibFuzzer/impl.go | 2 +- probes/fuzzedWithSwiftLibFuzzer/impl_test.go | 4 +-- .../impl.go | 2 +- .../impl_test.go | 4 +-- .../impl.go | 2 +- .../impl_test.go | 4 +-- probes/hasFSFOrOSIApprovedLicense/impl.go | 2 +- .../hasFSFOrOSIApprovedLicense/impl_test.go | 4 +-- probes/hasLicenseFile/impl.go | 2 +- probes/hasLicenseFile/impl_test.go | 4 +-- probes/hasLicenseFileAtTopDir/impl.go | 2 +- probes/hasLicenseFileAtTopDir/impl_test.go | 4 +-- probes/hasOSVVulnerabilities/impl.go | 2 +- probes/hasOSVVulnerabilities/impl_test.go | 8 +++--- probes/packagedWithAutomatedWorkflow/impl.go | 2 +- .../impl_test.go | 4 +-- probes/sastToolCodeQLInstalled/impl.go | 2 +- probes/sastToolCodeQLInstalled/impl_test.go | 4 +-- probes/sastToolRunsOnAllCommits/impl.go | 2 +- probes/sastToolRunsOnAllCommits/impl_test.go | 3 +-- probes/sastToolSonarInstalled/impl.go | 2 +- probes/sastToolSonarInstalled/impl_test.go | 4 +-- probes/securityPolicyContainsLinks/impl.go | 2 +- .../securityPolicyContainsLinks/impl_test.go | 4 +-- probes/securityPolicyContainsText/impl.go | 2 +- .../securityPolicyContainsText/impl_test.go | 4 +-- .../impl.go | 2 +- .../impl_test.go | 4 +-- probes/securityPolicyPresent/impl.go | 2 +- probes/securityPolicyPresent/impl_test.go | 4 +-- probes/toolDependabotInstalled/impl.go | 2 +- probes/toolDependabotInstalled/impl_test.go | 4 +-- probes/toolPyUpInstalled/impl.go | 2 +- probes/toolPyUpInstalled/impl_test.go | 4 +-- probes/toolRenovateInstalled/impl.go | 2 +- probes/toolRenovateInstalled/impl_test.go | 4 +-- remediation/remediations.go | 2 +- rule/rule.go | 7 +++-- rule/rule_test.go | 2 +- utests/utlib.go | 5 ++-- 158 files changed, 322 insertions(+), 374 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d926e3df145..b4b4e505264 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -58,6 +58,7 @@ linters: - misspell - nakedret - nestif + - nolintlint - predeclared - staticcheck - stylecheck @@ -152,6 +153,10 @@ linters-settings: - ptrToRefParam - typeUnparen - unnecessaryBlock + nolintlint: + # `//nolint` should mention specific linter such as `//nolint:my-linter` + # Overly broad directives can hide unrelated issues + require-specific: true wrapcheck: ignorePackageGlobs: - github.com/ossf/scorecard/v4/checks/fileparser diff --git a/attestor/policy/attestation_policy_test.go b/attestor/policy/attestation_policy_test.go index 0c1f991e875..8f2c201f859 100644 --- a/attestor/policy/attestation_policy_test.go +++ b/attestor/policy/attestation_policy_test.go @@ -170,7 +170,7 @@ func TestCheckPreventBinaryArtifacts(t *testing.T) { func TestCheckCodeReviewed(t *testing.T) { t.Parallel() - // nolint + //nolint:govet tests := []struct { err error raw *checker.RawResults @@ -385,7 +385,7 @@ func asPointer(s string) *string { func TestNoUnpinnedDependencies(t *testing.T) { t.Parallel() - // nolint + //nolint:govet tests := []struct { err error raw *checker.RawResults diff --git a/checker/check_result_test.go b/checker/check_result_test.go index 1ec48850340..42cc8a66823 100644 --- a/checker/check_result_test.go +++ b/checker/check_result_test.go @@ -50,7 +50,7 @@ func TestAggregateScores(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := AggregateScores(tt.args.scores...); got != tt.want { //nolint:govet + if got := AggregateScores(tt.args.scores...); got != tt.want { t.Errorf("AggregateScores() = %v, want %v", got, tt.want) } }) @@ -86,7 +86,7 @@ func TestAggregateScoresWithWeight(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := AggregateScoresWithWeight(tt.args.scores); got != tt.want { //nolint:govet + if got := AggregateScoresWithWeight(tt.args.scores); got != tt.want { t.Errorf("AggregateScoresWithWeight() = %v, want %v", got, tt.want) } }) @@ -132,8 +132,8 @@ func TestCreateProportionalScore(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CreateProportionalScore(tt.args.success, tt.args.total); got != tt.want { //nolint:govet - t.Errorf("CreateProportionalScore() = %v, want %v", got, tt.want) //nolint:govet + if got := CreateProportionalScore(tt.args.success, tt.args.total); got != tt.want { + t.Errorf("CreateProportionalScore() = %v, want %v", got, tt.want) } }) } @@ -438,8 +438,8 @@ func TestNormalizeReason(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := NormalizeReason(tt.args.reason, tt.args.score); got != tt.want { //nolint:govet - t.Errorf("NormalizeReason() = %v, want %v", got, tt.want) //nolint:govet + if got := NormalizeReason(tt.args.reason, tt.args.score); got != tt.want { + t.Errorf("NormalizeReason() = %v, want %v", got, tt.want) } }) } @@ -490,8 +490,8 @@ func TestCreateResultWithScore(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CreateResultWithScore(tt.args.name, tt.args.reason, tt.args.score); !cmp.Equal(got, tt.want) { //nolint:lll,govet - t.Errorf("CreateResultWithScore() = %v, want %v", got, cmp.Diff(got, tt.want)) //nolint:govet + if got := CreateResultWithScore(tt.args.name, tt.args.reason, tt.args.score); !cmp.Equal(got, tt.want) { + t.Errorf("CreateResultWithScore() = %v, want %v", got, cmp.Diff(got, tt.want)) } }) } @@ -545,8 +545,8 @@ func TestCreateProportionalScoreResult(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CreateProportionalScoreResult(tt.args.name, tt.args.reason, tt.args.b, tt.args.t); !cmp.Equal(got, tt.want) { //nolint:govet,lll - t.Errorf("CreateProportionalScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) //nolint:govet + if got := CreateProportionalScoreResult(tt.args.name, tt.args.reason, tt.args.b, tt.args.t); !cmp.Equal(got, tt.want) { //nolint:lll + t.Errorf("CreateProportionalScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) } }) } @@ -594,7 +594,7 @@ func TestCreateMaxScoreResult(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CreateMaxScoreResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { //nolint:govet + if got := CreateMaxScoreResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { t.Errorf("CreateMaxScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) } }) @@ -643,7 +643,7 @@ func TestCreateMinScoreResult(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CreateMinScoreResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { //nolint:govet + if got := CreateMinScoreResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { t.Errorf("CreateMinScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) } }) diff --git a/checker/client_test.go b/checker/client_test.go index 5084e3d2334..c1caf79cf13 100644 --- a/checker/client_test.go +++ b/checker/client_test.go @@ -20,9 +20,8 @@ import ( "github.com/ossf/scorecard/v4/log" ) -// nolint:paralleltest -// because we are using t.Setenv. -func TestGetClients(t *testing.T) { //nolint:gocognit +//nolint:paralleltest // because we are using t.Setenv. +func TestGetClients(t *testing.T) { type args struct { //nolint:govet ctx context.Context repoURI string diff --git a/checker/raw_result.go b/checker/raw_result.go index abac71eecf2..878e00af362 100644 --- a/checker/raw_result.go +++ b/checker/raw_result.go @@ -25,7 +25,8 @@ import ( // RawResults contains results before a policy // is applied. -// nolint +// +//nolint:govet type RawResults struct { BinaryArtifactResults BinaryArtifactData BranchProtectionResults BranchProtectionsData @@ -77,7 +78,6 @@ type PackagingData struct { } // Package represents a package. -// nolint type Package struct { // TODO: not supported yet. This needs to be unique across // ecosystems: purl, OSV, CPE, etc. diff --git a/checks/all_checks_test.go b/checks/all_checks_test.go index 276bc7d789f..3a0ff1e54c6 100644 --- a/checks/all_checks_test.go +++ b/checks/all_checks_test.go @@ -23,12 +23,12 @@ import ( func Test_registerCheck(t *testing.T) { t.Parallel() - //nolint + //nolint:govet type args struct { name string fn checker.CheckFn } - //nolint + //nolint:govet tests := []struct { name string args args diff --git a/checks/branch_protection_test.go b/checks/branch_protection_test.go index 035120a1486..c96a902b411 100644 --- a/checks/branch_protection_test.go +++ b/checks/branch_protection_test.go @@ -57,7 +57,6 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { rel1 := "release/v.1" sha := "8fb3cb86082b17144a80402f5367ae65f06083bd" - //nolint:goconst main := "main" trueVal := true falseVal := false @@ -65,7 +64,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { var oneVal int32 = 1 - //nolint + //nolint:govet tests := []struct { name string expected scut.TestReturn diff --git a/checks/code_review_test.go b/checks/code_review_test.go index 1b48c06093f..81d5d3675ad 100644 --- a/checks/code_review_test.go +++ b/checks/code_review_test.go @@ -30,8 +30,7 @@ import ( // TestCodeReview tests the code review checker. func TestCodereview(t *testing.T) { t.Parallel() - //fieldalignment lint issue. Ignoring it as it is not important for this test. - //nolint + //nolint:goerr113 tests := []struct { err error name string diff --git a/checks/contributors_test.go b/checks/contributors_test.go index d059325e8e2..9c162cff339 100644 --- a/checks/contributors_test.go +++ b/checks/contributors_test.go @@ -29,8 +29,6 @@ import ( // TestContributors tests the contributors check. func TestContributors(t *testing.T) { t.Parallel() - //fieldalignment lint issue. Ignoring it as it is not important for this test. - //nolint tests := []struct { err error name string @@ -61,7 +59,6 @@ func TestContributors(t *testing.T) { name: "Valid contributors with enough contributors and companies", contrib: []clients.User{ { - Companies: []string{"company1"}, NumContributions: 10, Organizations: []clients.User{ @@ -146,7 +143,7 @@ func TestContributors(t *testing.T) { }, }, { - err: errors.New("error"), + err: errors.New("error"), //nolint:goerr113 name: "Error getting contributors", contrib: []clients.User{}, expected: checker.CheckResult{ diff --git a/checks/dependency_update_tool.go b/checks/dependency_update_tool.go index b010511ad7b..4022b389796 100644 --- a/checks/dependency_update_tool.go +++ b/checks/dependency_update_tool.go @@ -26,7 +26,7 @@ import ( // CheckDependencyUpdateTool is the exported name for Automatic-Depdendency-Update. const CheckDependencyUpdateTool = "Dependency-Update-Tool" -// nolint +//nolint:gochecknoinits func init() { supportedRequestTypes := []checker.RequestType{ checker.FileBased, diff --git a/checks/dependency_update_tool_test.go b/checks/dependency_update_tool_test.go index e5d20fdfca0..05d56cef43f 100644 --- a/checks/dependency_update_tool_test.go +++ b/checks/dependency_update_tool_test.go @@ -32,7 +32,7 @@ const ( // TestDependencyUpdateTool tests the DependencyUpdateTool checker. func TestDependencyUpdateTool(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string wantErr bool diff --git a/checks/evaluation/binary_artifacts_test.go b/checks/evaluation/binary_artifacts_test.go index 7a4ccab29e4..ed7a0fa95a7 100644 --- a/checks/evaluation/binary_artifacts_test.go +++ b/checks/evaluation/binary_artifacts_test.go @@ -24,7 +24,7 @@ import ( // TestBinaryArtifacts tests the binary artifacts check. func TestBinaryArtifacts(t *testing.T) { t.Parallel() - //nolint + //nolint:govet type args struct { name string dl checker.DetailLogger diff --git a/checks/evaluation/ci_tests_test.go b/checks/evaluation/ci_tests_test.go index 8a1ab871645..22ddae1e14b 100644 --- a/checks/evaluation/ci_tests_test.go +++ b/checks/evaluation/ci_tests_test.go @@ -130,8 +130,6 @@ func Test_isTest(t *testing.T) { func Test_prHasSuccessfulCheck(t *testing.T) { t.Parallel() - //enabled nolint because this is a test - //nolint tests := []struct { name string args checker.RevisionCIInfo @@ -263,13 +261,13 @@ func Test_prHasSuccessStatus(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - got, err := prHasSuccessStatus(tt.args.r, tt.args.dl) //nolint:govet - if (err != nil) != tt.wantErr { //nolint:govet - t.Errorf("prHasSuccessStatus() error = %v, wantErr %v", err, tt.wantErr) //nolint:govet + got, err := prHasSuccessStatus(tt.args.r, tt.args.dl) + if (err != nil) != tt.wantErr { + t.Errorf("prHasSuccessStatus() error = %v, wantErr %v", err, tt.wantErr) return } - if got != tt.want { //nolint:govet - t.Errorf("prHasSuccessStatus() got = %v, want %v", got, tt.want) //nolint:govet + if got != tt.want { + t.Errorf("prHasSuccessStatus() got = %v, want %v", got, tt.want) } }) } @@ -360,7 +358,7 @@ func Test_prHasSuccessfulCheckAdditional(t *testing.T) { t.Errorf("prHasSuccessfulCheck() error = %v, wantErr %v", err, tt.wantErr) return } - if got != tt.want { //nolint:govet + if got != tt.want { t.Errorf("prHasSuccessfulCheck() got = %v, want %v", got, tt.want) } }) @@ -449,8 +447,8 @@ func TestCITests(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CITests(tt.args.in0, tt.args.c, tt.args.dl); got.Score != tt.want { //nolint:govet - t.Errorf("CITests() = %v, want %v", got.Score, tt.want) //nolint:govet + if got := CITests(tt.args.in0, tt.args.c, tt.args.dl); got.Score != tt.want { + t.Errorf("CITests() = %v, want %v", got.Score, tt.want) } }) } diff --git a/checks/evaluation/dependency_update_tool_test.go b/checks/evaluation/dependency_update_tool_test.go index 0dc19ed6634..1063929aace 100644 --- a/checks/evaluation/dependency_update_tool_test.go +++ b/checks/evaluation/dependency_update_tool_test.go @@ -25,7 +25,6 @@ import ( func TestDependencyUpdateTool(t *testing.T) { t.Parallel() - //nolint tests := []struct { name string findings []finding.Finding diff --git a/checks/evaluation/pinned_dependencies_test.go b/checks/evaluation/pinned_dependencies_test.go index f4e6616baa5..b4ee3e13372 100644 --- a/checks/evaluation/pinned_dependencies_test.go +++ b/checks/evaluation/pinned_dependencies_test.go @@ -27,7 +27,7 @@ import ( func Test_createScoreForGitHubActionsWorkflow(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string r worklowPinningResult @@ -884,7 +884,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { w *worklowPinningResult isGitHub bool } - tests := []struct { //nolint:govet + tests := []struct { name string want *worklowPinningResult args args diff --git a/checks/evaluation/security_policy_test.go b/checks/evaluation/security_policy_test.go index 2e3f9395d82..4a57164077f 100644 --- a/checks/evaluation/security_policy_test.go +++ b/checks/evaluation/security_policy_test.go @@ -25,7 +25,6 @@ import ( func TestSecurityPolicy(t *testing.T) { t.Parallel() - //nolint tests := []struct { name string findings []finding.Finding diff --git a/checks/evaluation/signed_releases.go b/checks/evaluation/signed_releases.go index f50c7895517..5feb11b680f 100644 --- a/checks/evaluation/signed_releases.go +++ b/checks/evaluation/signed_releases.go @@ -32,7 +32,8 @@ var ( const releaseLookBack = 5 // SignedReleases applies the score policy for the Signed-Releases check. -// nolint +// +//nolint:gocognit func SignedReleases(name string, dl checker.DetailLogger, r *checker.SignedReleasesData) checker.CheckResult { if r == nil { e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") diff --git a/checks/evaluation/vulnerabilities_test.go b/checks/evaluation/vulnerabilities_test.go index 639a4ef5712..3ed902d1175 100644 --- a/checks/evaluation/vulnerabilities_test.go +++ b/checks/evaluation/vulnerabilities_test.go @@ -25,18 +25,18 @@ import ( // TestVulnerabilities tests the vulnerabilities checker. func TestVulnerabilities(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string - findings []finding.Finding - result scut.TestReturn + findings []finding.Finding + result scut.TestReturn expected []struct { lineNumber uint } }{ { name: "no vulnerabilities", - findings: []finding.Finding { + findings: []finding.Finding{ { Probe: "hasOSVVulnerabilities", Outcome: finding.OutcomePositive, @@ -48,7 +48,7 @@ func TestVulnerabilities(t *testing.T) { }, { name: "three vulnerabilities", - findings: []finding.Finding { + findings: []finding.Finding{ { Probe: "hasOSVVulnerabilities", Outcome: finding.OutcomeNegative, @@ -63,13 +63,13 @@ func TestVulnerabilities(t *testing.T) { }, }, result: scut.TestReturn{ - Score: 7, + Score: 7, NumberOfWarn: 3, }, }, { name: "twelve vulnerabilities to check that score is not less than 0", - findings: []finding.Finding { + findings: []finding.Finding{ { Probe: "hasOSVVulnerabilities", Outcome: finding.OutcomeNegative, @@ -120,13 +120,13 @@ func TestVulnerabilities(t *testing.T) { }, }, result: scut.TestReturn{ - Score: 0, + Score: 0, NumberOfWarn: 12, }, }, { - name: "invalid findings", - findings: []finding.Finding {}, + name: "invalid findings", + findings: []finding.Finding{}, result: scut.TestReturn{ Score: -1, Error: sce.ErrScorecardInternal, diff --git a/checks/evaluation/webhooks_test.go b/checks/evaluation/webhooks_test.go index 4fefeb47e30..4a34f900f4e 100644 --- a/checks/evaluation/webhooks_test.go +++ b/checks/evaluation/webhooks_test.go @@ -25,7 +25,7 @@ import ( // TestWebhooks tests the webhooks check. func TestWebhooks(t *testing.T) { t.Parallel() - //nolint + //nolint:govet type args struct { name string dl checker.DetailLogger diff --git a/checks/fileparser/github_workflow_test.go b/checks/fileparser/github_workflow_test.go index 2c809467ac2..77d721dd405 100644 --- a/checks/fileparser/github_workflow_test.go +++ b/checks/fileparser/github_workflow_test.go @@ -401,7 +401,7 @@ func TestGetLineNumber(t *testing.T) { type args struct { pos *actionlint.Pos } - //nolint + //nolint:govet tests := []struct { name string args args @@ -488,7 +488,7 @@ func TestGetUses(t *testing.T) { type args struct { step *actionlint.Step } - //nolint + //nolint:govet tests := []struct { name string args args @@ -562,7 +562,7 @@ func Test_getWith(t *testing.T) { type args struct { step *actionlint.Step } - //nolint + //nolint:govet tests := []struct { name string args args @@ -648,7 +648,7 @@ func Test_getRun(t *testing.T) { type args struct { step *actionlint.Step } - //nolint + //nolint:govet tests := []struct { name string args args @@ -746,7 +746,7 @@ func Test_stepsMatch(t *testing.T) { stepToMatch *JobMatcherStep step *actionlint.Step } - //nolint + //nolint:govet tests := []struct { name string args args diff --git a/checks/fileparser/listing_test.go b/checks/fileparser/listing_test.go index 7d3e7cbfacb..86bbc74d0e0 100644 --- a/checks/fileparser/listing_test.go +++ b/checks/fileparser/listing_test.go @@ -135,7 +135,7 @@ func TestIsTemplateFile(t *testing.T) { // TestCheckFileContainsCommands tests if the content starts with a comment. func TestCheckFileContainsCommands(t *testing.T) { t.Parallel() - //nolint + //nolint:govet type args struct { content []byte comment string @@ -397,7 +397,7 @@ func Test_isTestdataFile(t *testing.T) { // TestOnMatchingFileContentDo tests the OnMatchingFileContent function. func TestOnMatchingFileContent(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string wantErr bool @@ -515,7 +515,7 @@ func TestOnMatchingFileContent(t *testing.T) { t.Parallel() x := func(path string, content []byte, args ...interface{}) (bool, error) { if tt.shouldFuncFail { - //nolint + //nolint:goerr113 return false, errors.New("test error") } if tt.shouldGetPredicateFail { @@ -542,8 +542,6 @@ func TestOnMatchingFileContent(t *testing.T) { } // TestOnAllFilesDo tests the OnAllFilesDo function. -// -//nolint:gocognit func TestOnAllFilesDo(t *testing.T) { t.Parallel() @@ -584,7 +582,7 @@ func TestOnAllFilesDo(t *testing.T) { alwaysFail := func(path string, args ...interface{}) (bool, error) { return false, errTest } - //nolint + //nolint:govet tests := []struct { name string onFile DoWhileTrueOnFilename diff --git a/checks/fuzzing_test.go b/checks/fuzzing_test.go index 6b031fa5c30..ca909758ea4 100644 --- a/checks/fuzzing_test.go +++ b/checks/fuzzing_test.go @@ -30,7 +30,7 @@ import ( // TestFuzzing is a test function for Fuzzing. func TestFuzzing(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string langs []clients.Language @@ -139,7 +139,7 @@ func TestFuzzing(t *testing.T) { mockFuzz.EXPECT().Search(gomock.Any()). DoAndReturn(func(q clients.SearchRequest) (clients.SearchResponse, error) { if tt.wantErr { - //nolint + //nolint:goerr113 return clients.SearchResponse{}, errors.New("error") } return tt.response, nil @@ -148,7 +148,7 @@ func TestFuzzing(t *testing.T) { mockFuzz.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() mockFuzz.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) (string, error) { if tt.wantErr { - //nolint + //nolint:goerr113 return "", errors.New("error") } return tt.fileContent, nil diff --git a/checks/maintained_test.go b/checks/maintained_test.go index 25f496de60e..d9fb337ae67 100644 --- a/checks/maintained_test.go +++ b/checks/maintained_test.go @@ -27,9 +27,9 @@ import ( scut "github.com/ossf/scorecard/v4/utests" ) -// ignoring the linter for cyclomatic complexity because it is a test func // TestMaintained tests the maintained check. -//nolint +// +//nolint:gocognit // ignoring the linter for cyclomatic complexity because it is a test func func Test_Maintained(t *testing.T) { t.Parallel() threeHundredDaysAgo := time.Now().AddDate(0, 0, -300) @@ -38,14 +38,13 @@ func Test_Maintained(t *testing.T) { oneDayAgo := time.Now().AddDate(0, 0, -1) ownerAssociation := clients.RepoAssociationOwner noneAssociation := clients.RepoAssociationNone - // fieldalignment lint issue. Ignoring it as it is not important for this test. someone := clients.User{ Login: "someone", } otheruser := clients.User{ Login: "someone-else", } - //nolint + //nolint:govet,goerr113 tests := []struct { err error name string @@ -339,7 +338,7 @@ func Test_Maintained(t *testing.T) { } return tt.isarchived, nil }) - + //nolint:nestif if tt.archiveerr == nil { mockRepo.EXPECT().ListCommits().DoAndReturn( func() ([]clients.Commit, error) { diff --git a/checks/permissions_test.go b/checks/permissions_test.go index 5ba90f2545e..0e72315608c 100644 --- a/checks/permissions_test.go +++ b/checks/permissions_test.go @@ -28,7 +28,7 @@ import ( scut "github.com/ossf/scorecard/v4/utests" ) -// nolint +//nolint:lll func TestGithubTokenPermissions(t *testing.T) { t.Parallel() diff --git a/checks/raw/branch_protection_test.go b/checks/raw/branch_protection_test.go index 1ae134d4155..4db6f385f65 100644 --- a/checks/raw/branch_protection_test.go +++ b/checks/raw/branch_protection_test.go @@ -33,7 +33,7 @@ var ( mainBranchName = "main" ) -// nolint: govet +//nolint:govet type branchArg struct { err error name string @@ -63,7 +63,7 @@ func (ba branchesArg) getBranch(b string) (*clients.BranchRef, error) { func TestBranchProtection(t *testing.T) { t.Parallel() - //nolint: govet + //nolint:govet tests := []struct { name string branches branchesArg diff --git a/checks/raw/dependency_update_tool_test.go b/checks/raw/dependency_update_tool_test.go index 618e606b752..7c65047b2e3 100644 --- a/checks/raw/dependency_update_tool_test.go +++ b/checks/raw/dependency_update_tool_test.go @@ -129,7 +129,7 @@ func Test_checkDependencyFileExists(t *testing.T) { // TestDependencyUpdateTool tests the DependencyUpdateTool function. func TestDependencyUpdateTool(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string wantErr bool diff --git a/checks/raw/fuzzing_test.go b/checks/raw/fuzzing_test.go index d2b855c30e1..d69430d8995 100644 --- a/checks/raw/fuzzing_test.go +++ b/checks/raw/fuzzing_test.go @@ -30,7 +30,7 @@ import ( // Test_checkOSSFuzz is a test function for checkOSSFuzz. func Test_checkOSSFuzz(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string want bool @@ -76,7 +76,7 @@ func Test_checkOSSFuzz(t *testing.T) { mockFuzz.EXPECT().Search(gomock.Any()). DoAndReturn(func(q clients.SearchRequest) (clients.SearchResponse, error) { if tt.wantErr { - //nolint + //nolint:goerr113 return clients.SearchResponse{}, errors.New("error") } return tt.response, nil @@ -106,7 +106,7 @@ func Test_checkOSSFuzz(t *testing.T) { // Test_checkCFLite is a test function for checkCFLite. func Test_checkCFLite(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string want bool @@ -138,7 +138,7 @@ func Test_checkCFLite(t *testing.T) { mockFuzz.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() mockFuzz.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) (string, error) { if tt.wantErr { - //nolint + //nolint:goerr113 return "", errors.New("error") } return tt.fileContent, nil @@ -160,7 +160,7 @@ func Test_checkCFLite(t *testing.T) { func Test_fuzzFileAndFuncMatchPattern(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string expectedFileMatch bool @@ -235,7 +235,7 @@ func Test_fuzzFileAndFuncMatchPattern(t *testing.T) { func Test_checkFuzzFunc(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string want bool @@ -490,7 +490,7 @@ func Test_checkFuzzFunc(t *testing.T) { mockClient.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() mockClient.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) ([]byte, error) { if tt.wantErr { - //nolint + //nolint:goerr113 return nil, errors.New("error") } return []byte(tt.fileContent), nil @@ -510,7 +510,6 @@ func Test_checkFuzzFunc(t *testing.T) { func Test_getProminentLanguages(t *testing.T) { t.Parallel() - //nolint tests := []struct { name string languages []clients.Language diff --git a/checks/raw/gitlab/packaging_test.go b/checks/raw/gitlab/packaging_test.go index 49fd91fe1f5..d300d20a62d 100644 --- a/checks/raw/gitlab/packaging_test.go +++ b/checks/raw/gitlab/packaging_test.go @@ -27,7 +27,7 @@ import ( func TestGitlabPackagingYamlCheck(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string lineNumber uint @@ -100,7 +100,7 @@ func TestGitlabPackagingYamlCheck(t *testing.T) { func TestGitlabPackagingPackager(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string lineNumber uint @@ -136,7 +136,7 @@ func TestGitlabPackagingPackager(t *testing.T) { moqRepoClient.EXPECT().GetFileContent(tt.filename). DoAndReturn(func(b string) ([]byte, error) { - //nolint: errcheck + //nolint:errcheck content, _ := os.ReadFile(b) return content, nil }).AnyTimes() @@ -150,7 +150,7 @@ func TestGitlabPackagingPackager(t *testing.T) { Repo: moqRepo, } - //nolint: errcheck + //nolint:errcheck packagingData, _ := Packaging(&req) if !tt.exists { diff --git a/checks/raw/license_test.go b/checks/raw/license_test.go index c6055ee90ec..ce5a603154e 100644 --- a/checks/raw/license_test.go +++ b/checks/raw/license_test.go @@ -646,7 +646,7 @@ func TestLicenseFileCheck(t *testing.T) { }, } - //nolint: paralleltest + //nolint:paralleltest for _, tt := range tests { tt := tt // Re-initializing variable so it is not changed while executing the closure below for _, ext := range tt.extensions { diff --git a/checks/raw/maintained_test.go b/checks/raw/maintained_test.go index 07f3b691d51..2df1ef7dd6f 100644 --- a/checks/raw/maintained_test.go +++ b/checks/raw/maintained_test.go @@ -78,7 +78,7 @@ func TestMaintained(t *testing.T) { }) t.Run("returns error if IsArchived fails", func(t *testing.T) { - mockRepoClient.EXPECT().IsArchived().Return(false, fmt.Errorf("some error")) // nolint: goerr113 + mockRepoClient.EXPECT().IsArchived().Return(false, fmt.Errorf("some error")) //nolint:goerr113 _, err := Maintained(req) if err == nil { @@ -88,7 +88,7 @@ func TestMaintained(t *testing.T) { t.Run("returns error if ListCommits fails", func(t *testing.T) { mockRepoClient.EXPECT().IsArchived().Return(false, nil) - mockRepoClient.EXPECT().ListCommits().Return(nil, fmt.Errorf("some error")) // nolint: goerr113 + mockRepoClient.EXPECT().ListCommits().Return(nil, fmt.Errorf("some error")) //nolint:goerr113 _, err := Maintained(req) if err == nil { @@ -99,7 +99,7 @@ func TestMaintained(t *testing.T) { t.Run("returns error if ListIssues fails", func(t *testing.T) { mockRepoClient.EXPECT().IsArchived().Return(false, nil) mockRepoClient.EXPECT().ListCommits().Return([]clients.Commit{}, nil) - mockRepoClient.EXPECT().ListIssues().Return(nil, fmt.Errorf("some error")) // nolint: goerr113 + mockRepoClient.EXPECT().ListIssues().Return(nil, fmt.Errorf("some error")) //nolint:goerr113 _, err := Maintained(req) if err == nil { @@ -111,7 +111,7 @@ func TestMaintained(t *testing.T) { mockRepoClient.EXPECT().IsArchived().Return(false, nil) mockRepoClient.EXPECT().ListCommits().Return([]clients.Commit{}, nil) mockRepoClient.EXPECT().ListIssues().Return([]clients.Issue{}, nil) - mockRepoClient.EXPECT().GetCreatedAt().Return(time.Time{}, fmt.Errorf("some error")) // nolint: goerr113 + mockRepoClient.EXPECT().GetCreatedAt().Return(time.Time{}, fmt.Errorf("some error")) //nolint:goerr113 _, err := Maintained(req) if err == nil { diff --git a/checks/raw/permissions.go b/checks/raw/permissions.go index 540fe4be223..c3c7132db44 100644 --- a/checks/raw/permissions.go +++ b/checks/raw/permissions.go @@ -93,7 +93,7 @@ var validateGitHubActionTokenPermissions fileparser.DoWhileTrueOnFileContent = f } // 1. Top-level permission definitions. - //nolint + //nolint:lll // https://docs.github.com/en/actions/reference/authentication-in-a-workflow#example-1-passing-the-github_token-as-an-input, // https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/, // https://docs.github.com/en/actions/reference/authentication-in-a-workflow#modifying-the-permissions-for-the-github_token. @@ -359,14 +359,13 @@ func isSARIFUploadWorkflow(workflow *actionlint.Workflow, fp string, pdata *perm } func isAllowedWorkflow(workflow *actionlint.Workflow, fp string, pdata *permissionCbData) bool { + //nolint:lll allowlist := map[string]bool{ - //nolint // CodeQl analysis workflow automatically sends sarif file to GitHub. // https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github#about-sarif-file-uploads-for-code-scanning. // `The CodeQL action uploads the SARIF file automatically when it completes analysis`. "github/codeql-action/analyze": true, - //nolint // Third-party scanning tools use the SARIF-upload action from code-ql. // https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github#uploading-a-code-scanning-analysis-with-github-actions // We only support CodeQl today. diff --git a/checks/raw/pinned_dependencies.go b/checks/raw/pinned_dependencies.go index 0d5fe791cb7..947856bba5f 100644 --- a/checks/raw/pinned_dependencies.go +++ b/checks/raw/pinned_dependencies.go @@ -323,7 +323,7 @@ var validateDockerfilesPinning fileparser.DoWhileTrueOnFileContent = func( } } - //nolint + //nolint:lll // The file need not have a FROM statement, // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/dockerfiles/partials/jupyter.partial.Dockerfile. diff --git a/checks/raw/pinned_dependencies_test.go b/checks/raw/pinned_dependencies_test.go index 4650b5b5661..02d8a17e6c0 100644 --- a/checks/raw/pinned_dependencies_test.go +++ b/checks/raw/pinned_dependencies_test.go @@ -34,7 +34,7 @@ import ( func TestGithubWorkflowPinning(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { warns int err error @@ -196,7 +196,7 @@ func TestGithubWorkflowPinningPattern(t *testing.T) { func TestNonGithubWorkflowPinning(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { warns int err error @@ -271,7 +271,7 @@ func TestNonGithubWorkflowPinning(t *testing.T) { func TestGithubWorkflowPkgManagerPinning(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { unpinned int processingErrors int @@ -331,7 +331,7 @@ func TestGithubWorkflowPkgManagerPinning(t *testing.T) { func TestDockerfilePinning(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { warns int err error @@ -579,7 +579,7 @@ func TestDockerfileInvalidFiles(t *testing.T) { func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { t.Parallel() - //nolint + //nolint:govet,lll tests := []struct { name string filename string @@ -594,7 +594,6 @@ func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { { name: "dockerfile downloads", filename: "./testdata/Dockerfile-download-lines", - //nolint expected: []struct { snippet string startLine uint @@ -678,7 +677,6 @@ func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { { name: "dockerfile downloads multi-run", filename: "./testdata/Dockerfile-download-multi-runs", - //nolint expected: []struct { snippet string startLine uint @@ -775,7 +773,7 @@ func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { func TestShellscriptInsecureDownloadsLineNumber(t *testing.T) { t.Parallel() - //nolint + //nolint:govet,lll tests := []struct { name string filename string @@ -789,7 +787,6 @@ func TestShellscriptInsecureDownloadsLineNumber(t *testing.T) { { name: "shell downloads", filename: "./testdata/shell-download-lines.sh", - //nolint expected: []struct { snippet string startLine uint @@ -960,7 +957,7 @@ func TestShellscriptInsecureDownloadsLineNumber(t *testing.T) { func TestDockerfilePinningWihoutHash(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { warns int err error @@ -1015,7 +1012,7 @@ func TestDockerfilePinningWihoutHash(t *testing.T) { func TestDockerfileScriptDownload(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { unpinned int processingErrors int @@ -1131,7 +1128,7 @@ func TestDockerfileScriptDownload(t *testing.T) { func TestDockerfileScriptDownloadInfo(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string filename string @@ -1185,7 +1182,7 @@ func TestDockerfileScriptDownloadInfo(t *testing.T) { func TestShellScriptDownload(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string filename string @@ -1268,7 +1265,7 @@ func TestShellScriptDownload(t *testing.T) { func TestShellScriptDownloadPinned(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string filename string @@ -1318,7 +1315,7 @@ func TestShellScriptDownloadPinned(t *testing.T) { func TestGitHubWorflowRunDownload(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string filename string diff --git a/checks/raw/security_policy_test.go b/checks/raw/security_policy_test.go index 51fefd346bb..24a6cb6eb19 100644 --- a/checks/raw/security_policy_test.go +++ b/checks/raw/security_policy_test.go @@ -63,7 +63,7 @@ func Test_isSecurityPolicyFilename(t *testing.T) { // TestSecurityPolicy tests the security policy. func TestSecurityPolicy(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string files []string diff --git a/checks/raw/shell_download_validate.go b/checks/raw/shell_download_validate.go index 19424b45c65..d5fd530142e 100644 --- a/checks/raw/shell_download_validate.go +++ b/checks/raw/shell_download_validate.go @@ -1089,7 +1089,6 @@ func validateShellFileAndRecord(pathfn string, startLine, endLine uint, content // TODO: support other interpreters. // Example: https://github.com/apache/airflow/blob/main/scripts/ci/kubernetes/ci_run_kubernetes_tests.sh#L75 // HOST_PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")')`` - // nolint if ok && isShellInterpreterOrCommand([]string{i}) { start, end := getLine(startLine, endLine, node) e := validateShellFileAndRecord(pathfn, start, end, diff --git a/checks/raw/vulnerabilities_test.go b/checks/raw/vulnerabilities_test.go index 14297ecf046..76da2f3514c 100644 --- a/checks/raw/vulnerabilities_test.go +++ b/checks/raw/vulnerabilities_test.go @@ -29,7 +29,7 @@ import ( func TestVulnerabilities(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string want checker.VulnerabilitiesData @@ -49,7 +49,7 @@ func TestVulnerabilities(t *testing.T) { { name: "err response", wantErr: true, - //nolint + //nolint:goerr113 err: errors.New("error"), vulnsResponse: clients.VulnerabilitiesResponse{}, }, @@ -93,7 +93,7 @@ func TestVulnerabilities(t *testing.T) { mockVulnClient.EXPECT().ListUnfixedVulnerabilities(context.TODO(), gomock.Any(), gomock.Any()).DoAndReturn( func(ctx context.Context, commit string, localPath string) (clients.VulnerabilitiesResponse, error) { if tt.vulnsError { - //nolint + //nolint:goerr113 return clients.VulnerabilitiesResponse{}, errors.New("error") } return tt.vulnsResponse, tt.err diff --git a/checks/raw/webhooks_test.go b/checks/raw/webhooks_test.go index 2fc23df1887..90f7d45e0a5 100644 --- a/checks/raw/webhooks_test.go +++ b/checks/raw/webhooks_test.go @@ -29,7 +29,7 @@ import ( func TestWebhooks(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string err error diff --git a/checks/sast_test.go b/checks/sast_test.go index 7bbb4345f75..1f296fcdc13 100644 --- a/checks/sast_test.go +++ b/checks/sast_test.go @@ -34,7 +34,7 @@ import ( func Test_SAST(t *testing.T) { t.Parallel() - //nolint: govet, goerr113 + //nolint:govet,goerr113 tests := []struct { name string err error diff --git a/checks/security_policy_test.go b/checks/security_policy_test.go index cf759d180a1..ef4386a798d 100644 --- a/checks/security_policy_test.go +++ b/checks/security_policy_test.go @@ -28,7 +28,7 @@ import ( func TestSecurityPolicy(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { name string path string diff --git a/checks/signed_releases_test.go b/checks/signed_releases_test.go index 71cd68b61f8..cfdaeaca355 100644 --- a/checks/signed_releases_test.go +++ b/checks/signed_releases_test.go @@ -28,8 +28,6 @@ import ( func TestSignedRelease(t *testing.T) { t.Parallel() - //fieldalignment lint issue. Ignoring it as it is not important for this test. - //nolint tests := []struct { err error name string @@ -363,12 +361,13 @@ func TestSignedRelease(t *testing.T) { Score: 8, }, }, + { name: "Error getting releases", - err: errors.New("Error getting releases"), + err: errors.New("Error getting releases"), //nolint:goerr113 expected: checker.CheckResult{ Score: -1, - Error: errors.New("Error getting releases"), + Error: errors.New("Error getting releases"), //nolint:goerr113 }, }, } diff --git a/checks/webhook_test.go b/checks/webhook_test.go index 05c35f8e576..df9c1b2dc24 100644 --- a/checks/webhook_test.go +++ b/checks/webhook_test.go @@ -26,7 +26,7 @@ import ( scut "github.com/ossf/scorecard/v4/utests" ) -//nolint:tparallel,paralleltest // since t.Setenv is used +//nolint:paralleltest // since t.Setenv is used func TestWebhooks(t *testing.T) { tests := []struct { expected checker.CheckResult diff --git a/clients/cii_http_client.go b/clients/cii_http_client.go index 0e3de359379..44374be7cc4 100644 --- a/clients/cii_http_client.go +++ b/clients/cii_http_client.go @@ -38,7 +38,7 @@ func (transport *expBackoffTransport) RoundTrip(req *http.Request) (*http.Respon for i := 0; i < int(transport.numRetries); i++ { resp, err := http.DefaultClient.Do(req) if err != nil || resp.StatusCode != http.StatusTooManyRequests { - //nolint: wrapcheck + //nolint:wrapcheck return resp, err } time.Sleep(time.Duration(math.Pow(2, float64(i))) * time.Second) diff --git a/clients/git/client_test.go b/clients/git/client_test.go index 98e132b9c9f..ce2d175fc34 100644 --- a/clients/git/client_test.go +++ b/clients/git/client_test.go @@ -36,7 +36,7 @@ func createTestRepo(t *testing.T) (path string) { t.Fatalf("Failed to create temporary directory: %v", err) } t.Cleanup(func() { - os.RemoveAll(dir) // nolint:errcheck + os.RemoveAll(dir) }) r, err := gitV5.PlainInit(dir, false) if err != nil { diff --git a/clients/githubrepo/checkruns.go b/clients/githubrepo/checkruns.go index b0479124ea0..6aad3107340 100644 --- a/clients/githubrepo/checkruns.go +++ b/clients/githubrepo/checkruns.go @@ -67,7 +67,7 @@ type checkRunsGraphqlData struct { type checkRunsByRef = map[string][]clients.CheckRun -// nolint: govet +//nolint:govet type checkrunsHandler struct { client *github.Client graphClient *githubv4.Client diff --git a/clients/githubrepo/graphql.go b/clients/githubrepo/graphql.go index 93e4a9afbb4..42b9adb3a65 100644 --- a/clients/githubrepo/graphql.go +++ b/clients/githubrepo/graphql.go @@ -106,7 +106,7 @@ type graphqlData struct { } `graphql:"object(expression: $commitExpression)"` Issues struct { Nodes []struct { - //nolint: revive,stylecheck // naming according to githubv4 convention. + //nolint:revive,stylecheck // naming according to githubv4 convention. Url *string AuthorAssociation *string Author struct { @@ -239,7 +239,6 @@ func (handler *graphqlHandler) isArchived() (bool, error) { return handler.archived, nil } -// nolint func commitsFrom(data *graphqlData, repoOwner, repoName string) ([]clients.Commit, error) { ret := make([]clients.Commit, 0) for _, commit := range data.Repository.Object.Commit.History.Nodes { diff --git a/clients/githubrepo/repo_test.go b/clients/githubrepo/repo_test.go index 689b6c94684..b0fdca7703d 100644 --- a/clients/githubrepo/repo_test.go +++ b/clients/githubrepo/repo_test.go @@ -20,8 +20,7 @@ import ( "github.com/google/go-cmp/cmp" ) -// nolint:paralleltest -// because we are using t.Setenv. +//nolint:paralleltest // because we are using t.Setenv. func TestRepoURL_IsValid(t *testing.T) { tests := []struct { name string diff --git a/clients/githubrepo/roundtripper/rate_limit_test.go b/clients/githubrepo/roundtripper/rate_limit_test.go index 9f60b33faf4..494467489fc 100644 --- a/clients/githubrepo/roundtripper/rate_limit_test.go +++ b/clients/githubrepo/roundtripper/rate_limit_test.go @@ -27,27 +27,28 @@ func TestRoundTrip(t *testing.T) { var requestCount int ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Customize the response headers and body based on the test scenario + //nolint:errcheck switch r.URL.Path { case "/error": w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Internal Server Error")) // nolint: errcheck + w.Write([]byte("Internal Server Error")) case "/retry": requestCount++ if requestCount == 2 { // Second request: Return successful response w.Header().Set("X-RateLimit-Remaining", "10") w.WriteHeader(http.StatusOK) - w.Write([]byte("Success")) // nolint: errcheck + w.Write([]byte("Success")) } else { // First request: Return Retry-After header w.Header().Set("Retry-After", "1") w.WriteHeader(http.StatusTooManyRequests) - w.Write([]byte("Rate Limit Exceeded")) // nolint: errcheck + w.Write([]byte("Rate Limit Exceeded")) } case "/success": w.Header().Set("X-RateLimit-Remaining", "10") w.WriteHeader(http.StatusOK) - w.Write([]byte("Success")) // nolint: errcheck + w.Write([]byte("Success")) } })) t.Cleanup(func() { diff --git a/clients/githubrepo/roundtripper/roundtripper.go b/clients/githubrepo/roundtripper/roundtripper.go index 5a6752f4e53..0d46ff1cd6d 100644 --- a/clients/githubrepo/roundtripper/roundtripper.go +++ b/clients/githubrepo/roundtripper/roundtripper.go @@ -17,7 +17,7 @@ package roundtripper import ( "context" - "fmt" + "errors" "net/http" "os" "strconv" @@ -37,11 +37,13 @@ const ( githubAppInstallationID = "GITHUB_APP_INSTALLATION_ID" ) +var errGithubCredentials = errors.New("an error occurred while getting GitHub credentials") + // NewTransport returns a configured http.Transport for use with GitHub. func NewTransport(ctx context.Context, logger *log.Logger) http.RoundTripper { transport := http.DefaultTransport - //nolint + //nolint:nestif if tokenAccessor := tokens.MakeTokenAccessor(); tokenAccessor != nil { // Use GitHub PAT transport = makeGitHubTransport(transport, tokenAccessor) @@ -60,7 +62,8 @@ func NewTransport(ctx context.Context, logger *log.Logger) http.RoundTripper { } } else { // TODO(log): Improve error message - logger.Error(fmt.Errorf("an error occurred while getting GitHub credentials"), "GitHub token env var is not set. Please read https://github.com/ossf/scorecard#authentication") + //nolint:lll + logger.Error(errGithubCredentials, "GitHub token env var is not set. Please read https://github.com/ossf/scorecard#authentication") } return MakeCensusTransport(MakeRateLimitedTransport(transport, logger)) diff --git a/clients/githubrepo/roundtripper/tokens/server/main.go b/clients/githubrepo/roundtripper/tokens/server/main.go index 3a06bf56047..f5e4e9e5baa 100644 --- a/clients/githubrepo/roundtripper/tokens/server/main.go +++ b/clients/githubrepo/roundtripper/tokens/server/main.go @@ -36,13 +36,13 @@ func main() { } rpc.HandleHTTP() - //nolint: gosec // using `localhost:8080` for gosec102 causes connection refused errors. + //nolint:gosec // using `localhost:8080` for gosec102 causes connection refused errors. l, err := net.Listen("tcp", ":8080") if err != nil { panic(err) } - //nolint: gosec // internal server. + //nolint:gosec // internal server. if err := http.Serve(l, nil); err != nil { panic(err) } diff --git a/clients/githubrepo/tarball.go b/clients/githubrepo/tarball.go index 3ba40fdfe83..8888e2f26b6 100644 --- a/clients/githubrepo/tarball.go +++ b/clients/githubrepo/tarball.go @@ -161,7 +161,7 @@ func (handler *tarballHandler) getTarball() error { return nil } -// nolint: gocognit +//nolint:gocognit func (handler *tarballHandler) extractTarball() error { in, err := os.OpenFile(handler.tempTarFile, os.O_RDONLY, 0o644) if err != nil { @@ -213,7 +213,7 @@ func (handler *tarballHandler) extractTarball() error { return fmt.Errorf("os.Create: %w", err) } - //nolint: gosec + //nolint:gosec // Potential for DoS vulnerability via decompression bomb. // Since such an attack will only impact a single shard, ignoring this for now. if _, err := io.Copy(outFile, tr); err != nil { diff --git a/clients/githubrepo/tarball_test.go b/clients/githubrepo/tarball_test.go index c046675f11e..106877dbdf7 100644 --- a/clients/githubrepo/tarball_test.go +++ b/clients/githubrepo/tarball_test.go @@ -79,7 +79,7 @@ func setup(inputFile string) (tarballHandler, error) { return tarballHandler, nil } -// nolint: gocognit +//nolint:gocognit func TestExtractTarball(t *testing.T) { t.Parallel() testcases := []struct { diff --git a/clients/gitlabrepo/branches.go b/clients/gitlabrepo/branches.go index 33f43112e37..3cfb561545f 100644 --- a/clients/gitlabrepo/branches.go +++ b/clients/gitlabrepo/branches.go @@ -62,7 +62,7 @@ type ( options ...gitlab.RequestOptionFunc) (*gitlab.ProjectApprovals, *gitlab.Response, error) ) -// nolint: nestif +//nolint:nestif func (handler *branchesHandler) setup() error { handler.once.Do(func() { if !strings.EqualFold(handler.repourl.commitSHA, clients.HeadSHA) { diff --git a/clients/gitlabrepo/branches_test.go b/clients/gitlabrepo/branches_test.go index 447bbf9b490..9f5f2eb5aea 100644 --- a/clients/gitlabrepo/branches_test.go +++ b/clients/gitlabrepo/branches_test.go @@ -110,10 +110,10 @@ func TestGetBranches(t *testing.T) { handler.once.Do(func() {}) - // nolint: errcheck + //nolint:errcheck br, _ := handler.getBranch(tt.branchName) - // nolint: unconvert + //nolint:unconvert if string(*br.Name) != tt.expectedBranchName { t.Errorf("Branch Name (%s) didn't match expected value (%s)", *br.Name, tt.expectedBranchName) } diff --git a/clients/gitlabrepo/contributors.go b/clients/gitlabrepo/contributors.go index 596c5a73fa2..4e14d60a071 100644 --- a/clients/gitlabrepo/contributors.go +++ b/clients/gitlabrepo/contributors.go @@ -62,7 +62,7 @@ func (handler *contributorsHandler) retrieveContributors(project string) ([]*git }, ) if err != nil { - //nolint wrapcheck + //nolint:wrapcheck return nil, err } @@ -78,7 +78,7 @@ func (handler *contributorsHandler) retrieveContributors(project string) ([]*git func (handler *contributorsHandler) retrieveUsers(queryName string) ([]*gitlab.User, error) { users, _, err := handler.glClient.Search.Users(queryName, &gitlab.SearchOptions{}) if err != nil { - //nolint wrapcheck + //nolint:wrapcheck return nil, err } return users, nil diff --git a/clients/gitlabrepo/graphql.go b/clients/gitlabrepo/graphql.go index 4318e289c88..df4e17919a3 100644 --- a/clients/gitlabrepo/graphql.go +++ b/clients/gitlabrepo/graphql.go @@ -28,7 +28,6 @@ import ( "golang.org/x/oauth2" ) -//nolint:govet type graphqlHandler struct { err error client *http.Client @@ -49,7 +48,6 @@ func (handler *graphqlHandler) init(ctx context.Context, repourl *repoURL) { handler.graphClient = graphql.NewClient(fmt.Sprintf("%s/api/graphql", repourl.Host()), handler.client) } -//nolint:govet type graphqlData struct { Project struct { MergeRequests struct { diff --git a/clients/gitlabrepo/tarball.go b/clients/gitlabrepo/tarball.go index 61b48a69fe1..be0b42ffcaf 100644 --- a/clients/gitlabrepo/tarball.go +++ b/clients/gitlabrepo/tarball.go @@ -204,7 +204,7 @@ func (handler *tarballHandler) apiFunction(url, tempDir string, repoFile *os.Fil return nil } -// nolint: gocognit +//nolint:gocognit func (handler *tarballHandler) extractTarball() error { in, err := os.OpenFile(handler.tempTarFile, os.O_RDONLY, 0o644) if err != nil { @@ -256,7 +256,7 @@ func (handler *tarballHandler) extractTarball() error { return fmt.Errorf("os.Create: %w", err) } - //nolint: gosec + //nolint:gosec // Potential for DoS vulnerability via decompression bomb. // Since such an attack will only impact a single shard, ignoring this for now. if _, err := io.Copy(outFile, tr); err != nil { diff --git a/clients/gitlabrepo/tarball_test.go b/clients/gitlabrepo/tarball_test.go index c9c4d571075..75ad34e87e6 100644 --- a/clients/gitlabrepo/tarball_test.go +++ b/clients/gitlabrepo/tarball_test.go @@ -71,7 +71,7 @@ func setup(inputFile string) (tarballHandler, error) { return tarballHandler, nil } -// nolint: gocognit +//nolint:gocognit func TestExtractTarball(t *testing.T) { t.Parallel() testcases := []struct { diff --git a/cmd/internal/nuget/client.go b/cmd/internal/nuget/client.go index 20b6682522a..7eb23e4cfab 100644 --- a/cmd/internal/nuget/client.go +++ b/cmd/internal/nuget/client.go @@ -58,11 +58,11 @@ func (n packageRegistrationCatalogRoot) latestVersion(manager pmc.Client) (strin page := n.Pages[pageIndex] if page.Packages == nil { err := decodeResponseFromClient(func() (*http.Response, error) { - //nolint: wrapcheck + //nolint:wrapcheck return manager.GetURI(page.ID) }, func(rc io.ReadCloser) error { - //nolint: wrapcheck + //nolint:wrapcheck return json.NewDecoder(rc).Decode(&page) }, "nuget package registration page") if err != nil { @@ -170,12 +170,12 @@ func (c *NugetClient) packageSpec(packageBaseURL, registrationBaseURL, packageNa } packageSpecResults := &packageNuspec{} err = decodeResponseFromClient(func() (*http.Response, error) { - //nolint: wrapcheck + //nolint:wrapcheck return c.Manager.Get( packageBaseURL+"%[1]v/"+lastPackageVersion+"/%[1]v.nuspec", lowerCasePackageName) }, func(rc io.ReadCloser) error { - //nolint: wrapcheck + //nolint:wrapcheck return xml.NewDecoder(rc).Decode(packageSpecResults) }, "nuget package spec") @@ -193,11 +193,11 @@ func (c *NugetClient) baseUrls() (string, string, error) { indexURL := "https://api.nuget.org/v3/index.json" indexResults := &indexResults{} err := decodeResponseFromClient(func() (*http.Response, error) { - //nolint: wrapcheck + //nolint:wrapcheck return c.Manager.GetURI(indexURL) }, func(rc io.ReadCloser) error { - //nolint: wrapcheck + //nolint:wrapcheck return json.NewDecoder(rc).Decode(indexResults) }, "nuget index json") if err != nil { @@ -219,11 +219,11 @@ func (c *NugetClient) baseUrls() (string, string, error) { func (c *NugetClient) latestListedVersion(baseURL, packageName string) (string, error) { packageRegistrationCatalogRoot := &packageRegistrationCatalogRoot{} err := decodeResponseFromClient(func() (*http.Response, error) { - //nolint: wrapcheck + //nolint:wrapcheck return c.Manager.Get(baseURL+"%s/index.json", packageName) }, func(rc io.ReadCloser) error { - //nolint: wrapcheck + //nolint:wrapcheck return json.NewDecoder(rc).Decode(packageRegistrationCatalogRoot) }, "nuget package registration index json") if err != nil { @@ -240,8 +240,8 @@ func isSupportedProjectURL(projectURL string) bool { // Nuget semver diverges from Semantic Versioning. // This method returns the Nuget represntation of version and pre release strings. -// nolint: lll // long URL -// more info: https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#where-nugetversion-diverges-from-semantic-versioning +// +//nolint:lll // https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#where-nugetversion-diverges-from-semantic-versioning func parseNugetSemVer(versionString string) (base, preReleaseSuffix string) { metadataAndVersion := strings.Split(versionString, "+") prereleaseAndVersions := strings.Split(metadataAndVersion[0], "-") diff --git a/cmd/internal/nuget/client_test.go b/cmd/internal/nuget/client_test.go index 5b25789f276..de369fdd3f9 100644 --- a/cmd/internal/nuget/client_test.go +++ b/cmd/internal/nuget/client_test.go @@ -390,7 +390,7 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { resultPackageRegistrationPages: []resultPackagePage{}, resultPackageSpec: "", }, - //nolint + //nolint:lll want: "internal error: failed to parse nuget package registration index json: invalid character 'e' in literal true (expecting 'r')", wantErr: true, }, @@ -443,7 +443,7 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { }, resultPackageSpec: "", }, - //nolint + //nolint:lll want: "internal error: failed to parse nuget package registration page: invalid character 'e' in literal true (expecting 'r')", wantErr: true, }, @@ -514,7 +514,7 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { resultPackageSpec: "", version: "", }, - //nolint + //nolint:lll want: "internal error: failed to parse nuget package registration index json: failed to unmarshal json: json: cannot unmarshal number into Go struct field Alias.listed of type bool", wantErr: true, }, @@ -580,7 +580,7 @@ func nugetIndexOrPageTestResults(url string, test *nugetTest) (*http.Response, e urlResponseIndex := slices.IndexFunc(test.args.resultPackageRegistrationPages, func(page resultPackagePage) bool { return page.url == url }) if urlResponseIndex == -1 { - //nolint + //nolint:goerr113 return nil, errors.New("error") } page := test.args.resultPackageRegistrationPages[urlResponseIndex] @@ -597,13 +597,13 @@ func nugetPackageIndexAndSpecResponse(t *testing.T, url string, test *nugetTest) } t.Errorf("fetchGitRepositoryFromNuget() version = %v, expected version = %v", url, test.args.version) } - //nolint + //nolint:goerr113 return nil, errors.New("error") } func testResult(wantErr bool, responseFileName string) (*http.Response, error) { if wantErr && responseFileName == "" { - //nolint + //nolint:goerr113 return nil, errors.New("error") } if wantErr && responseFileName == "text" { diff --git a/cmd/internal/packagemanager/client.go b/cmd/internal/packagemanager/client.go index 5e3ee1f00df..6ce2651a05d 100644 --- a/cmd/internal/packagemanager/client.go +++ b/cmd/internal/packagemanager/client.go @@ -29,22 +29,20 @@ type Client interface { type PackageManagerClient struct{} -// nolint: noctx func (c *PackageManagerClient) Get(url, packageName string) (*http.Response, error) { return c.getRemoteURL(fmt.Sprintf(url, packageName)) } -// nolint: noctx func (c *PackageManagerClient) GetURI(url string) (*http.Response, error) { return c.getRemoteURL(url) } -// nolint: noctx +//nolint:noctx func (c *PackageManagerClient) getRemoteURL(url string) (*http.Response, error) { const timeout = 10 client := &http.Client{ Timeout: timeout * time.Second, } - //nolint + //nolint:wrapcheck return client.Get(url) } diff --git a/cmd/internal/packagemanager/client_test.go b/cmd/internal/packagemanager/client_test.go index 04ffd40e783..56e6e7a1d23 100644 --- a/cmd/internal/packagemanager/client_test.go +++ b/cmd/internal/packagemanager/client_test.go @@ -51,10 +51,8 @@ func Test_GetURI_calls_client_get_with_input(t *testing.T) { if r.URL.Path != tt.wantURL { t.Errorf("Expected to request '%s', got: %s", tt.wantURL, r.URL.Path) } - // nolint w.WriteHeader(http.StatusOK) - // nolint - w.Write([]byte(tt.wantResponse)) + w.Write([]byte(tt.wantResponse)) //nolint:errcheck })) defer server.Close() client := PackageManagerClient{} @@ -107,10 +105,8 @@ func Test_Get_calls_client_get_with_input(t *testing.T) { if r.URL.Path != tt.wantURL { t.Errorf("Expected to request '%s', got: %s", tt.wantURL, r.URL.Path) } - // nolint w.WriteHeader(http.StatusOK) - // nolint - w.Write([]byte(tt.wantResponse)) + w.Write([]byte(tt.wantResponse)) //nolint:errcheck })) defer server.Close() client := PackageManagerClient{} diff --git a/cmd/package_managers_test.go b/cmd/package_managers_test.go index f2c8482524a..8b70eac8fc7 100644 --- a/cmd/package_managers_test.go +++ b/cmd/package_managers_test.go @@ -141,7 +141,7 @@ func Test_fetchGitRepositoryFromNPM(t *testing.T) { p.EXPECT().Get(gomock.Any(), tt.args.packageName). DoAndReturn(func(url, packageName string) (*http.Response, error) { if tt.wantErr && tt.args.result == "" { - //nolint + //nolint:goerr113 return nil, errors.New("error") } @@ -314,10 +314,9 @@ func Test_fetchGitRepositoryFromPYPI(t *testing.T) { }{ { name: "fetchGitRepositoryFromPYPI", - //nolint args: args{ packageName: "some-package", - //nolint + //nolint:lll result: ` { "info": { @@ -451,7 +450,7 @@ func Test_fetchGitRepositoryFromPYPI(t *testing.T) { p.EXPECT().Get(gomock.Any(), tt.args.packageName). DoAndReturn(func(url, packageName string) (*http.Response, error) { if tt.wantErr && tt.args.result == "" { - //nolint + //nolint:goerr113 return nil, errors.New("error") } @@ -486,10 +485,9 @@ func Test_fetchGitRepositoryFromRubyGems(t *testing.T) { }{ { name: "fetchGitRepositoryFromPYPI", - //nolint args: args{ packageName: "npm-package", - //nolint + //nolint:lll result: ` { "name": "color", @@ -609,10 +607,9 @@ func Test_fetchGitRepositoryFromRubyGems(t *testing.T) { }, { name: "empty project url", - //nolint args: args{ packageName: "npm-package", - //nolint + //nolint:lll result: ` { "name": "color", @@ -720,7 +717,7 @@ func Test_fetchGitRepositoryFromRubyGems(t *testing.T) { p.EXPECT().Get(gomock.Any(), tt.args.packageName). DoAndReturn(func(url, packageName string) (*http.Response, error) { if tt.wantErr && tt.args.result == "" { - //nolint + //nolint:goerr113 return nil, errors.New("error") } @@ -755,22 +752,18 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { }{ { name: "Return repository from nuget client", - //nolint args: args{ packageName: "nuget-package", - //nolint - result: "nuget", + result: "nuget", }, want: "nuget", wantErr: false, }, { name: "Error from nuget client", - //nolint args: args{ packageName: "nuget-package", - //nolint - result: "", + result: "", }, want: "", wantErr: true, @@ -785,7 +778,7 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { n.EXPECT().GitRepositoryByPackageName(tt.args.packageName). DoAndReturn(func(packageName string) (string, error) { if tt.wantErr && tt.args.result == "" { - //nolint + //nolint:goerr113 return "", errors.New("error") } diff --git a/cmd/serve.go b/cmd/serve.go index 31825104527..0aecc321681 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -96,7 +96,7 @@ func serveCmd(o *options.Options) *cobra.Command { port = "8080" } logger.Info("Listening on localhost:" + port + "\n") - //nolint: gosec // unsused. + //nolint:gosec // unsused. err = http.ListenAndServe(fmt.Sprintf("0.0.0.0:%s", port), nil) if err != nil { // TODO(log): Should this actually panic? diff --git a/cron/config/config.go b/cron/config/config.go index c359254a5c6..a3c1a091457 100644 --- a/cron/config/config.go +++ b/cron/config/config.go @@ -154,7 +154,7 @@ func getFloat64ConfigValue(envVar string, byteValue []byte, fieldName, configNam switch value.Kind() { case reflect.String: - //nolint: wrapcheck, gomnd + //nolint:wrapcheck,gomnd return strconv.ParseFloat(value.String(), 64) case reflect.Float32, reflect.Float64: return value.Float(), nil diff --git a/cron/config/config_test.go b/cron/config/config_test.go index 536393a2335..c1356a3a754 100644 --- a/cron/config/config_test.go +++ b/cron/config/config_test.go @@ -70,7 +70,7 @@ func getByteValueFromFile(filename string) ([]byte, error) { if filename == "" { return nil, nil } - //nolint + //nolint:wrapcheck return os.ReadFile(filename) } diff --git a/cron/data/summary.go b/cron/data/summary.go index bacbcd3a58a..f401f8c50cc 100644 --- a/cron/data/summary.go +++ b/cron/data/summary.go @@ -126,7 +126,7 @@ func GetBucketSummary(ctx context.Context, bucketURL string) (*BucketSummary, er summary.getOrCreate(creationTime).shardsExpected = int(metadata.GetNumShard()) summary.getOrCreate(creationTime).shardMetadata = keyData default: - //nolint: goerr113 + //nolint:goerr113 return nil, fmt.Errorf("found unrecognized file: %s", key) } } diff --git a/cron/internal/bq/main.go b/cron/internal/bq/main.go index efb3ad10d31..73b7454c3a2 100644 --- a/cron/internal/bq/main.go +++ b/cron/internal/bq/main.go @@ -50,7 +50,7 @@ func transferDataToBq(ctx context.Context, if webhookURL == "" { continue } - //nolint: noctx, gosec // variable URL is ok here. + //nolint:noctx,gosec // variable URL is ok here. resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(shards.Metadata())) if err != nil { return fmt.Errorf("error during http.Post to %s: %w", webhookURL, err) diff --git a/cron/internal/controller/bucket_test.go b/cron/internal/controller/bucket_test.go index a3eb695b1b1..2b041353174 100644 --- a/cron/internal/controller/bucket_test.go +++ b/cron/internal/controller/bucket_test.go @@ -20,9 +20,8 @@ import ( "testing" ) -//nolint:tparallel,paralleltest // since t.Setenv is used +//nolint:paralleltest // since t.Setenv is used func TestGetPrefix(t *testing.T) { - //nolint:govet testcases := []struct { name string url string diff --git a/cron/internal/format/json_test.go b/cron/internal/format/json_test.go index e1a25b036a9..293fa7400f3 100644 --- a/cron/internal/format/json_test.go +++ b/cron/internal/format/json_test.go @@ -66,7 +66,7 @@ func jsonMockDocRead() *mockDoc { return &m } -// nolint +//nolint:gocognit func TestJSONOutput(t *testing.T) { t.Parallel() @@ -80,7 +80,7 @@ func TestJSONOutput(t *testing.T) { } checkDocs := jsonMockDocRead() - + //nolint:govet tests := []struct { name string expected string diff --git a/cron/internal/format/mock_doc.go b/cron/internal/format/mock_doc.go index 782d3fbc81b..ebcde284f3e 100644 --- a/cron/internal/format/mock_doc.go +++ b/cron/internal/format/mock_doc.go @@ -70,8 +70,7 @@ type mockDoc struct { } func (d *mockDoc) GetCheck(name string) (docs.CheckDoc, error) { - //nolint: gosimple - m, _ := d.checks[name] + m := d.checks[name] return &m, nil } diff --git a/cron/internal/format/schema_gen_test.go b/cron/internal/format/schema_gen_test.go index f267b0182ae..aff35ddbc04 100644 --- a/cron/internal/format/schema_gen_test.go +++ b/cron/internal/format/schema_gen_test.go @@ -22,10 +22,10 @@ import ( "github.com/google/go-cmp/cmp" ) -//nolint func Test_GenerateBQSchema(t *testing.T) { t.Parallel() + //nolint:govet tests := []struct { name string path string @@ -80,10 +80,10 @@ func Test_GenerateBQSchema(t *testing.T) { } } -//nolint func Test_GenerateJSONSchema(t *testing.T) { t.Parallel() + //nolint:govet tests := []struct { name string path string diff --git a/cron/internal/pubsub/publisher_test.go b/cron/internal/pubsub/publisher_test.go index 8e53f1f8c57..0860e77c71f 100644 --- a/cron/internal/pubsub/publisher_test.go +++ b/cron/internal/pubsub/publisher_test.go @@ -33,13 +33,13 @@ func (topic *mockSucceedTopic) Send(ctx context.Context, msg *pubsub.Message) er type mockFailTopic struct{} func (topic *mockFailTopic) Send(ctx context.Context, msg *pubsub.Message) error { - //nolint: goerr113 + //nolint:goerr113 return fmt.Errorf("mockFailTopic failed to send") } func TestPublish(t *testing.T) { t.Parallel() - //nolint: govet + //nolint:govet testcases := []struct { numErrors uint64 name string diff --git a/cron/internal/pubsub/subscriber_gocloud.go b/cron/internal/pubsub/subscriber_gocloud.go index fcf1699a319..52225b41fec 100644 --- a/cron/internal/pubsub/subscriber_gocloud.go +++ b/cron/internal/pubsub/subscriber_gocloud.go @@ -37,7 +37,6 @@ type gocloudSubscriber struct { msg *pubsub.Message } -//nolint:unused,deadcode func createGocloudSubscriber(ctx context.Context, subscriptionURL string) (*gocloudSubscriber, error) { subscription, err := pubsub.OpenSubscription(ctx, subscriptionURL) if err != nil { diff --git a/cron/internal/pubsub/subscriber_gocloud_test.go b/cron/internal/pubsub/subscriber_gocloud_test.go index 92d23c2ac7a..791b8d77874 100644 --- a/cron/internal/pubsub/subscriber_gocloud_test.go +++ b/cron/internal/pubsub/subscriber_gocloud_test.go @@ -65,7 +65,7 @@ func TestSubscriber(t *testing.T) { { name: "ReceiveFails", hasErrOnReceive: true, - //nolint: goerr113 + //nolint:goerr113 errOnReceive: errors.New("mock Receive failure"), }, { @@ -78,7 +78,7 @@ func TestSubscriber(t *testing.T) { }, }, hasErrOnShutdown: true, - //nolint: goerr113 + //nolint:goerr113 errOnShutdown: errors.New("mock Shutdown close"), }, } diff --git a/cron/internal/webhook/main.go b/cron/internal/webhook/main.go index 9724f79a0fa..fac59c04ddd 100644 --- a/cron/internal/webhook/main.go +++ b/cron/internal/webhook/main.go @@ -81,7 +81,7 @@ func scriptHandler(w http.ResponseWriter, r *http.Request) { func main() { http.HandleFunc("/", scriptHandler) log.Printf("Starting HTTP server on port 8080 ...\n") - // nolint:gosec // internal server. + //nolint:gosec // internal server. if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } diff --git a/cron/internal/worker/main.go b/cron/internal/worker/main.go index e38108e3f05..c516312927d 100644 --- a/cron/internal/worker/main.go +++ b/cron/internal/worker/main.go @@ -220,7 +220,7 @@ func processRequest(ctx context.Context, } errorMsg := fmt.Sprintf("check %s has a runtime error: %v", check.Name, check.Error) if !(*ignoreRuntimeErrors) { - //nolint: goerr113 + //nolint:goerr113 return errors.New(errorMsg) } // TODO(log): Previously Warn. Consider logging an error here. diff --git a/dependencydiff/dependencydiff_test.go b/dependencydiff/dependencydiff_test.go index e936a6aa648..3717371af0a 100644 --- a/dependencydiff/dependencydiff_test.go +++ b/dependencydiff/dependencydiff_test.go @@ -25,7 +25,7 @@ import ( ) func Test_initRepoAndClientByChecks(t *testing.T) { - //nolint + //nolint:govet tests := []struct { name string dCtx dependencydiffContext @@ -112,7 +112,7 @@ func Test_getScorecardCheckResults(t *testing.T) { } func Test_mapDependencyEcosystemNaming(t *testing.T) { - //nolint + //nolint:govet tests := []struct { name string deps []dependency @@ -167,7 +167,6 @@ func Test_mapDependencyEcosystemNaming(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - //nolint err := mapDependencyEcosystemNaming(tt.deps) if tt.errWanted != nil && errors.Is(tt.errWanted, err) { t.Errorf("not a wanted error, want:%v, got:%v", tt.errWanted, err) @@ -178,7 +177,6 @@ func Test_mapDependencyEcosystemNaming(t *testing.T) { } func Test_isSpecifiedByUser(t *testing.T) { - //nolint tests := []struct { name string ct pkg.ChangeType @@ -216,7 +214,6 @@ func Test_isSpecifiedByUser(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - //nolint result := isSpecifiedByUser(tt.ct, tt.changeTypesToCheck) if result != tt.resultWanted { t.Errorf("result (%v) != result wanted (%v)", result, tt.resultWanted) diff --git a/dependencydiff/mapping.go b/dependencydiff/mapping.go index 285fd88173d..ef0a102460a 100644 --- a/dependencydiff/mapping.go +++ b/dependencydiff/mapping.go @@ -22,7 +22,6 @@ import ( type ecosystem string // OSV ecosystem naming data source: https://ossf.github.io/osv-schema/#affectedpackage-field -//nolint const ( // The Go ecosystem. ecosystemGo ecosystem = "Go" @@ -30,7 +29,7 @@ const ( // The NPM ecosystem. ecosystemNpm ecosystem = "npm" - // The Android ecosystem + // The Android ecosystem. ecosystemAndroid ecosystem = "Android" //nolint:unused // The crates.io ecosystem for RUST. diff --git a/docs/checks/impl.go b/docs/checks/impl.go index b65d9620b76..82c5d6f0e30 100644 --- a/docs/checks/impl.go +++ b/docs/checks/impl.go @@ -50,7 +50,7 @@ func Read() (Doc, error) { func (d *DocImpl) GetCheck(name string) (CheckDoc, error) { ic, exists := d.internaldoc.InternalChecks[name] if !exists { - //nolint: wrapcheck + //nolint:wrapcheck return nil, sce.CreateInternal(errCheckNotExist, "") } // Set the name and URL. @@ -63,7 +63,7 @@ func (d *DocImpl) GetCheck(name string) (CheckDoc, error) { func (d *DocImpl) GetChecks() []CheckDoc { var checks []CheckDoc for k := range d.internaldoc.InternalChecks { - //nolint: errcheck + //nolint:errcheck check, _ := d.GetCheck(k) checks = append(checks, check) } diff --git a/docs/checks/internal/generate/main.go b/docs/checks/internal/generate/main.go index 21604eaa17b..ec4680821b4 100644 --- a/docs/checks/internal/generate/main.go +++ b/docs/checks/internal/generate/main.go @@ -23,7 +23,7 @@ import ( func main() { if len(os.Args) != 2 { - //nolint: goerr113 + //nolint:goerr113 panic(fmt.Errorf("usage: %s filename", os.Args[0])) } yamlFile := os.Args[1] diff --git a/finding/finding.go b/finding/finding.go index a296efc1ed8..39f06175cee 100644 --- a/finding/finding.go +++ b/finding/finding.go @@ -43,7 +43,8 @@ const ( ) // Location represents the location of a finding. -// nolint: govet +// +//nolint:govet type Location struct { Type FileType `json:"type"` Path string `json:"path"` @@ -93,7 +94,8 @@ const ( ) // Finding represents a finding. -// nolint: govet +// +//nolint:govet type Finding struct { Probe string `json:"probe"` Outcome Outcome `json:"outcome"` @@ -117,7 +119,7 @@ var errInvalid = errors.New("invalid") func FromBytes(content []byte, probeID string) (*Finding, error) { p, err := probe.FromBytes(content, probeID) if err != nil { - // nolint + //nolint:wrapcheck return nil, err } f := &Finding{ diff --git a/finding/finding_test.go b/finding/finding_test.go index 50f1a7b1934..33d792e9787 100644 --- a/finding/finding_test.go +++ b/finding/finding_test.go @@ -38,7 +38,7 @@ func Test_FromBytes(t *testing.T) { positiveOutcome := OutcomePositive negativeOutcome := OutcomeNegative t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string id string diff --git a/finding/probe/probe.go b/finding/probe/probe.go index 4e83a3a6a7a..ce084aae835 100644 --- a/finding/probe/probe.go +++ b/finding/probe/probe.go @@ -51,14 +51,12 @@ type Remediation struct { Effort RemediationEffort `json:"effort"` } -// nolint: govet type yamlRemediation struct { Text []string `yaml:"text"` Markdown []string `yaml:"markdown"` Effort RemediationEffort `yaml:"effort"` } -// nolint: govet type yamlProbe struct { ID string `yaml:"id"` Short string `yaml:"short"` @@ -67,7 +65,7 @@ type yamlProbe struct { Remediation yamlRemediation `yaml:"remediation"` } -// nolint: govet +//nolint:govet type Probe struct { ID string Short string @@ -154,7 +152,6 @@ func (r *RemediationEffort) UnmarshalYAML(n *yaml.Node) error { return fmt.Errorf("%w: %w", errInvalid, err) } - // nolint:goconst switch n.Value { case "Low": *r = RemediationEffortLow diff --git a/finding/probe/probe_test.go b/finding/probe/probe_test.go index 2fe1a8a82ad..1095a2adc1f 100644 --- a/finding/probe/probe_test.go +++ b/finding/probe/probe_test.go @@ -29,7 +29,7 @@ func errCmp(e1, e2 error) bool { func Test_FromBytes(t *testing.T) { t.Parallel() - // nolint: govet + //nolint:govet tests := []struct { name string id string diff --git a/options/options_test.go b/options/options_test.go index 8098e8ebc90..91e5ed9c350 100644 --- a/options/options_test.go +++ b/options/options_test.go @@ -16,12 +16,10 @@ package options import ( - "os" "testing" ) -// Cannot run parallel tests because of the ENV variables. -// nolint +//nolint:paralleltest // because we are using t.Setenv. func TestOptions_Validate(t *testing.T) { type fields struct { Repo string @@ -110,8 +108,7 @@ func TestOptions_Validate(t *testing.T) { EnableScorecardV6: tt.fields.EnableScorecardV6, } if o.EnableSarif { - os.Setenv(EnvVarEnableSarif, "1") - defer os.Unsetenv(EnvVarEnableSarif) + t.Setenv(EnvVarEnableSarif, "1") } if err := o.Validate(); (err != nil) != tt.wantErr { diff --git a/pkg/json.go b/pkg/json.go index fd81223cffa..f98766decef 100644 --- a/pkg/json.go +++ b/pkg/json.go @@ -27,7 +27,6 @@ import ( "github.com/ossf/scorecard/v4/log" ) -//nolint:govet type jsonCheckResult struct { Name string Details []string @@ -49,7 +48,7 @@ type jsonCheckDocumentationV2 struct { // Can be extended if needed. } -// nolint: govet +//nolint:govet type jsonCheckResultV2 struct { Details []string `json:"details"` Score int `json:"score"` diff --git a/pkg/json_probe_results.go b/pkg/json_probe_results.go index 633d39a47d4..386d0dc94d7 100644 --- a/pkg/json_probe_results.go +++ b/pkg/json_probe_results.go @@ -24,8 +24,6 @@ import ( ) // JSONScorecardProbeResult exports results as JSON for flat findings without checks. -// -//nolint:govet type JSONScorecardProbeResult struct { Date string `json:"date"` Repo jsonRepoV2 `json:"repo"` diff --git a/pkg/json_raw_results.go b/pkg/json_raw_results.go index 629bee123b9..5d63cacfec8 100644 --- a/pkg/json_raw_results.go +++ b/pkg/json_raw_results.go @@ -307,7 +307,7 @@ func (r *jsonScorecardRawResult) addTokenPermissionsRawResults(tp *checker.Token } if t.LocationType == nil { - //nolint + //nolint:goerr113 return errors.New("locationType is nil") } @@ -351,7 +351,7 @@ func (r *jsonScorecardRawResult) addPackagingRawResults(pk *checker.PackagingDat continue } if p.File == nil { - //nolint + //nolint:goerr113 return errors.New("file field is nil") } diff --git a/pkg/json_test.go b/pkg/json_test.go index 285a0694018..7b39de2b251 100644 --- a/pkg/json_test.go +++ b/pkg/json_test.go @@ -66,7 +66,7 @@ func jsonMockDocRead() *mockDoc { return &m } -// nolint +//nolint:gocognit func TestJSONOutput(t *testing.T) { t.Parallel() @@ -82,6 +82,7 @@ func TestJSONOutput(t *testing.T) { checkDocs := jsonMockDocRead() + //nolint:govet tests := []struct { name string expected string diff --git a/pkg/mock_doc.go b/pkg/mock_doc.go index 1baa2a8432c..dd565acf09d 100644 --- a/pkg/mock_doc.go +++ b/pkg/mock_doc.go @@ -70,8 +70,7 @@ type mockDoc struct { } func (d *mockDoc) GetCheck(name string) (docs.CheckDoc, error) { - //nolint: gosimple - m, _ := d.checks[name] + m := d.checks[name] return &m, nil } diff --git a/pkg/sarif.go b/pkg/sarif.go index 037907a274e..dfa418439bf 100644 --- a/pkg/sarif.go +++ b/pkg/sarif.go @@ -40,7 +40,6 @@ type text struct { Text string `json:"text,omitempty"` } -// nolint type region struct { StartLine *uint `json:"startLine,omitempty"` EndLine *uint `json:"endLine,omitempty"` @@ -62,16 +61,15 @@ type physicalLocation struct { ArtifactLocation artifactLocation `json:"artifactLocation"` } -//nolint:govet +//nolint:govet,lll type location struct { PhysicalLocation physicalLocation `json:"physicalLocation"` - //nolint // This is optional https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#location-object. Message *text `json:"message,omitempty"` HasRemediation bool `json:"-"` } -// nolint +//nolint:govet type relatedLocation struct { ID int `json:"id"` PhysicalLocation physicalLocation `json:"physicalLocation"` @@ -124,7 +122,7 @@ type tool struct { Driver driver `json:"driver"` } -// nolint +//nolint:govet type result struct { RuleID string `json:"ruleId"` Level string `json:"level,omitempty"` // Optional. @@ -338,7 +336,7 @@ func detailsToLocations(details []checker.CheckDetail, ) []location { locs := []location{} - //nolint + //nolint:lll // Populate the locations. // Note https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/sarif-support-for-code-scanning#result-object // "Only the first value of this array is used. All other values are ignored." @@ -429,7 +427,7 @@ func createSARIFRun(uri, toolName, version, commit string, t time.Time, return run{ Tool: createSARIFTool(uri, toolName, version), Results: []result{}, - //nolint + //nolint:lll // See https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#runautomationdetails-object. AutomationDetails: automationDetails{ // Time formatting: https://pkg.go.dev/time#pkg-constants. @@ -613,7 +611,7 @@ func (r *ScorecardResult) AsSARIF(showDetails bool, logLevel log.Level, writer io.Writer, checkDocs docs.Doc, policy *spol.ScorecardPolicy, opts *options.Options, ) error { - //nolint + //nolint:lll // https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/sarif-v2.1.0-cs01.html. // We only support GitHub-supported properties: // see https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/sarif-support-for-code-scanning#supported-sarif-output-file-properties, @@ -621,8 +619,8 @@ func (r *ScorecardResult) AsSARIF(showDetails bool, logLevel log.Level, sarif := createSARIFHeader() runs := make(map[string]*run) - //nolint for _, check := range r.Checks { + check := check doc, err := checkDocs.GetCheck(check.Name) if err != nil { return sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("GetCheck: %v: %s", err, check.Name)) @@ -692,6 +690,7 @@ func (r *ScorecardResult) AsSARIF(showDetails bool, logLevel log.Level, run.Results = append(run.Results, cr) } else { for _, loc := range locs { + loc := loc // Use the location's message (check's detail's message) as message. msg := messageWithScore(loc.Message.Text, check.Score) cr := createSARIFCheckResult(RuleIndex, sarifCheckID, msg, &loc) diff --git a/pkg/sarif_test.go b/pkg/sarif_test.go index 1fa37e52362..49d8e7190e9 100644 --- a/pkg/sarif_test.go +++ b/pkg/sarif_test.go @@ -99,18 +99,9 @@ func sarifMockDocRead() *mockDoc { return &m } -// nolint func TestSARIFOutput(t *testing.T) { t.Parallel() - type Check struct { - Risk string `yaml:"-"` - Short string `yaml:"short"` - Description string `yaml:"description"` - Remediation []string `yaml:"remediation"` - Tags string `yaml:"tags"` - } - repoCommit := "68bc59901773ab4c051dfcea0cc4201a1567ab32" scorecardCommit := "ccbc59901773ab4c051dfcea0cc4201a1567abdd" scorecardVersion := "1.2.3" @@ -122,6 +113,7 @@ func TestSARIFOutput(t *testing.T) { checkDocs := sarifMockDocRead() + //nolint:govet tests := []struct { name string expected string diff --git a/pkg/scorecard_result.go b/pkg/scorecard_result.go index 6a005f94c98..ed06013b897 100644 --- a/pkg/scorecard_result.go +++ b/pkg/scorecard_result.go @@ -44,7 +44,6 @@ type RepoInfo struct { } // ScorecardResult struct is returned on a successful Scorecard run. -// nolint type ScorecardResult struct { Repo RepoInfo Date time.Time diff --git a/policy/policy_test.go b/policy/policy_test.go index 654eb224670..5fec445f73f 100644 --- a/policy/policy_test.go +++ b/policy/policy_test.go @@ -29,7 +29,7 @@ import ( func TestPolicyRead(t *testing.T) { t.Parallel() - //nolint + //nolint:govet tests := []struct { err error name string diff --git a/probes/contributorsFromOrgOrCompany/impl.go b/probes/contributorsFromOrgOrCompany/impl.go index 25cab7b652f..24c9730efa7 100644 --- a/probes/contributorsFromOrgOrCompany/impl.go +++ b/probes/contributorsFromOrgOrCompany/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package contributorsFromOrgOrCompany import ( diff --git a/probes/contributorsFromOrgOrCompany/impl_test.go b/probes/contributorsFromOrgOrCompany/impl_test.go index 006436b4b0f..0efe4c7c827 100644 --- a/probes/contributorsFromOrgOrCompany/impl_test.go +++ b/probes/contributorsFromOrgOrCompany/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package contributorsFromOrgOrCompany import ( @@ -37,7 +37,7 @@ type User struct { func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithCLibFuzzer/impl.go b/probes/fuzzedWithCLibFuzzer/impl.go index b2d198c033c..a04f445281a 100644 --- a/probes/fuzzedWithCLibFuzzer/impl.go +++ b/probes/fuzzedWithCLibFuzzer/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithCLibFuzzer import ( diff --git a/probes/fuzzedWithCLibFuzzer/impl_test.go b/probes/fuzzedWithCLibFuzzer/impl_test.go index e4fe0dce5bf..a3db752b409 100644 --- a/probes/fuzzedWithCLibFuzzer/impl_test.go +++ b/probes/fuzzedWithCLibFuzzer/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithCLibFuzzer import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithClusterFuzzLite/impl.go b/probes/fuzzedWithClusterFuzzLite/impl.go index f869b92796c..24bc7fdb957 100644 --- a/probes/fuzzedWithClusterFuzzLite/impl.go +++ b/probes/fuzzedWithClusterFuzzLite/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithClusterFuzzLite import ( diff --git a/probes/fuzzedWithClusterFuzzLite/impl_test.go b/probes/fuzzedWithClusterFuzzLite/impl_test.go index 4c64e562783..e2ff255c2e6 100644 --- a/probes/fuzzedWithClusterFuzzLite/impl_test.go +++ b/probes/fuzzedWithClusterFuzzLite/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithClusterFuzzLite import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithCppLibFuzzer/impl.go b/probes/fuzzedWithCppLibFuzzer/impl.go index cbbb3146243..d16beb42b17 100644 --- a/probes/fuzzedWithCppLibFuzzer/impl.go +++ b/probes/fuzzedWithCppLibFuzzer/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithCppLibFuzzer import ( diff --git a/probes/fuzzedWithCppLibFuzzer/impl_test.go b/probes/fuzzedWithCppLibFuzzer/impl_test.go index 48ea6bae6d9..5f9a99af353 100644 --- a/probes/fuzzedWithCppLibFuzzer/impl_test.go +++ b/probes/fuzzedWithCppLibFuzzer/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithCppLibFuzzer import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithGoNative/impl.go b/probes/fuzzedWithGoNative/impl.go index 7afbac7c1fc..98d82b26bf3 100644 --- a/probes/fuzzedWithGoNative/impl.go +++ b/probes/fuzzedWithGoNative/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithGoNative import ( diff --git a/probes/fuzzedWithGoNative/impl_test.go b/probes/fuzzedWithGoNative/impl_test.go index 5362ff2d17f..a65c14d1dc5 100644 --- a/probes/fuzzedWithGoNative/impl_test.go +++ b/probes/fuzzedWithGoNative/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithGoNative import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithJavaJazzerFuzzer/impl.go b/probes/fuzzedWithJavaJazzerFuzzer/impl.go index 4fb46f0b113..76e78c12491 100644 --- a/probes/fuzzedWithJavaJazzerFuzzer/impl.go +++ b/probes/fuzzedWithJavaJazzerFuzzer/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithJavaJazzerFuzzer import ( diff --git a/probes/fuzzedWithJavaJazzerFuzzer/impl_test.go b/probes/fuzzedWithJavaJazzerFuzzer/impl_test.go index 3dcb5bb3549..125cdff34ca 100644 --- a/probes/fuzzedWithJavaJazzerFuzzer/impl_test.go +++ b/probes/fuzzedWithJavaJazzerFuzzer/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithJavaJazzerFuzzer import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithOSSFuzz/impl.go b/probes/fuzzedWithOSSFuzz/impl.go index 5a695a606a5..86648b4835c 100644 --- a/probes/fuzzedWithOSSFuzz/impl.go +++ b/probes/fuzzedWithOSSFuzz/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithOSSFuzz import ( diff --git a/probes/fuzzedWithOSSFuzz/impl_test.go b/probes/fuzzedWithOSSFuzz/impl_test.go index ed3f66bc48f..dda926bcf08 100644 --- a/probes/fuzzedWithOSSFuzz/impl_test.go +++ b/probes/fuzzedWithOSSFuzz/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithOSSFuzz import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithPropertyBasedHaskell/impl.go b/probes/fuzzedWithPropertyBasedHaskell/impl.go index 4d62c9e9883..0e2ea0e3264 100644 --- a/probes/fuzzedWithPropertyBasedHaskell/impl.go +++ b/probes/fuzzedWithPropertyBasedHaskell/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPropertyBasedHaskell import ( diff --git a/probes/fuzzedWithPropertyBasedHaskell/impl_test.go b/probes/fuzzedWithPropertyBasedHaskell/impl_test.go index 341e8bd5b31..dea7fa81e51 100644 --- a/probes/fuzzedWithPropertyBasedHaskell/impl_test.go +++ b/probes/fuzzedWithPropertyBasedHaskell/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPropertyBasedHaskell import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithPropertyBasedJavascript/impl.go b/probes/fuzzedWithPropertyBasedJavascript/impl.go index cc129453169..ee1c4a24f9c 100644 --- a/probes/fuzzedWithPropertyBasedJavascript/impl.go +++ b/probes/fuzzedWithPropertyBasedJavascript/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPropertyBasedJavascript import ( diff --git a/probes/fuzzedWithPropertyBasedJavascript/impl_test.go b/probes/fuzzedWithPropertyBasedJavascript/impl_test.go index 818d4b40515..04432415bd8 100644 --- a/probes/fuzzedWithPropertyBasedJavascript/impl_test.go +++ b/probes/fuzzedWithPropertyBasedJavascript/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPropertyBasedJavascript import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithPropertyBasedTypescript/impl.go b/probes/fuzzedWithPropertyBasedTypescript/impl.go index 94b7e35b67f..0c1f7daa5f7 100644 --- a/probes/fuzzedWithPropertyBasedTypescript/impl.go +++ b/probes/fuzzedWithPropertyBasedTypescript/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPropertyBasedTypescript import ( diff --git a/probes/fuzzedWithPropertyBasedTypescript/impl_test.go b/probes/fuzzedWithPropertyBasedTypescript/impl_test.go index 597f15edda9..f43728a8f5c 100644 --- a/probes/fuzzedWithPropertyBasedTypescript/impl_test.go +++ b/probes/fuzzedWithPropertyBasedTypescript/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPropertyBasedTypescript import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithPythonAtheris/impl.go b/probes/fuzzedWithPythonAtheris/impl.go index eb26c2981a0..d615817d506 100644 --- a/probes/fuzzedWithPythonAtheris/impl.go +++ b/probes/fuzzedWithPythonAtheris/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPythonAtheris import ( diff --git a/probes/fuzzedWithPythonAtheris/impl_test.go b/probes/fuzzedWithPythonAtheris/impl_test.go index 34c918bb102..606d30c58c4 100644 --- a/probes/fuzzedWithPythonAtheris/impl_test.go +++ b/probes/fuzzedWithPythonAtheris/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithPythonAtheris import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithRustCargofuzz/impl.go b/probes/fuzzedWithRustCargofuzz/impl.go index df531b4af25..0b036556edc 100644 --- a/probes/fuzzedWithRustCargofuzz/impl.go +++ b/probes/fuzzedWithRustCargofuzz/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithRustCargofuzz import ( diff --git a/probes/fuzzedWithRustCargofuzz/impl_test.go b/probes/fuzzedWithRustCargofuzz/impl_test.go index bfcfb052692..5ea0e1dfe3e 100644 --- a/probes/fuzzedWithRustCargofuzz/impl_test.go +++ b/probes/fuzzedWithRustCargofuzz/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithRustCargofuzz import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/fuzzedWithSwiftLibFuzzer/impl.go b/probes/fuzzedWithSwiftLibFuzzer/impl.go index 7236d18e870..ec39b45942a 100644 --- a/probes/fuzzedWithSwiftLibFuzzer/impl.go +++ b/probes/fuzzedWithSwiftLibFuzzer/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithSwiftLibFuzzer import ( diff --git a/probes/fuzzedWithSwiftLibFuzzer/impl_test.go b/probes/fuzzedWithSwiftLibFuzzer/impl_test.go index 5f3be6a4b65..91c6b4b902e 100644 --- a/probes/fuzzedWithSwiftLibFuzzer/impl_test.go +++ b/probes/fuzzedWithSwiftLibFuzzer/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package fuzzedWithSwiftLibFuzzer import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/hasDangerousWorkflowScriptInjection/impl.go b/probes/hasDangerousWorkflowScriptInjection/impl.go index e3b91f95988..15180a603a0 100644 --- a/probes/hasDangerousWorkflowScriptInjection/impl.go +++ b/probes/hasDangerousWorkflowScriptInjection/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasDangerousWorkflowScriptInjection import ( diff --git a/probes/hasDangerousWorkflowScriptInjection/impl_test.go b/probes/hasDangerousWorkflowScriptInjection/impl_test.go index 9b35a4b7708..1a08859f01f 100644 --- a/probes/hasDangerousWorkflowScriptInjection/impl_test.go +++ b/probes/hasDangerousWorkflowScriptInjection/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasDangerousWorkflowScriptInjection import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/hasDangerousWorkflowUntrustedCheckout/impl.go b/probes/hasDangerousWorkflowUntrustedCheckout/impl.go index d3bd59f5269..1ca81205bcf 100644 --- a/probes/hasDangerousWorkflowUntrustedCheckout/impl.go +++ b/probes/hasDangerousWorkflowUntrustedCheckout/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasDangerousWorkflowUntrustedCheckout import ( diff --git a/probes/hasDangerousWorkflowUntrustedCheckout/impl_test.go b/probes/hasDangerousWorkflowUntrustedCheckout/impl_test.go index b3aed7b7162..3d37f42ee8f 100644 --- a/probes/hasDangerousWorkflowUntrustedCheckout/impl_test.go +++ b/probes/hasDangerousWorkflowUntrustedCheckout/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasDangerousWorkflowUntrustedCheckout import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/hasFSFOrOSIApprovedLicense/impl.go b/probes/hasFSFOrOSIApprovedLicense/impl.go index d6a5a823551..37949be20a7 100644 --- a/probes/hasFSFOrOSIApprovedLicense/impl.go +++ b/probes/hasFSFOrOSIApprovedLicense/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasFSFOrOSIApprovedLicense import ( diff --git a/probes/hasFSFOrOSIApprovedLicense/impl_test.go b/probes/hasFSFOrOSIApprovedLicense/impl_test.go index a02ed9476e0..743d3272881 100644 --- a/probes/hasFSFOrOSIApprovedLicense/impl_test.go +++ b/probes/hasFSFOrOSIApprovedLicense/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasFSFOrOSIApprovedLicense import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/hasLicenseFile/impl.go b/probes/hasLicenseFile/impl.go index 14a37f4cce6..e68f0384345 100644 --- a/probes/hasLicenseFile/impl.go +++ b/probes/hasLicenseFile/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasLicenseFile import ( diff --git a/probes/hasLicenseFile/impl_test.go b/probes/hasLicenseFile/impl_test.go index db97b0d0677..c4326f61541 100644 --- a/probes/hasLicenseFile/impl_test.go +++ b/probes/hasLicenseFile/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasLicenseFile import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/hasLicenseFileAtTopDir/impl.go b/probes/hasLicenseFileAtTopDir/impl.go index 0955f758b4b..5acda37247e 100644 --- a/probes/hasLicenseFileAtTopDir/impl.go +++ b/probes/hasLicenseFileAtTopDir/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasLicenseFileAtTopDir import ( diff --git a/probes/hasLicenseFileAtTopDir/impl_test.go b/probes/hasLicenseFileAtTopDir/impl_test.go index fe892cd27f4..7c0ad14863b 100644 --- a/probes/hasLicenseFileAtTopDir/impl_test.go +++ b/probes/hasLicenseFileAtTopDir/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasLicenseFileAtTopDir import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/hasOSVVulnerabilities/impl.go b/probes/hasOSVVulnerabilities/impl.go index f3452268510..9f4e704d52f 100644 --- a/probes/hasOSVVulnerabilities/impl.go +++ b/probes/hasOSVVulnerabilities/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasOSVVulnerabilities import ( diff --git a/probes/hasOSVVulnerabilities/impl_test.go b/probes/hasOSVVulnerabilities/impl_test.go index 65b50e83d99..46d64ecbe51 100644 --- a/probes/hasOSVVulnerabilities/impl_test.go +++ b/probes/hasOSVVulnerabilities/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package hasOSVVulnerabilities import ( @@ -29,7 +29,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults @@ -88,11 +88,11 @@ func Test_Run(t *testing.T) { Probe: "hasOSVVulnerabilities", Message: "Project is vulnerable to: foo", Remediation: &probe.Remediation{ - //nolint + //nolint:lll Text: `Fix the foo by following information from https://osv.dev/foo. If the vulnerability is in a dependency, update the dependency to a non-vulnerable version. If no update is available, consider whether to remove the dependency. If you believe the vulnerability does not affect your project, the vulnerability can be ignored. To ignore, create an osv-scanner.toml file next to the dependency manifest (e.g. package-lock.json) and specify the ID to ignore and reason. Details on the structure of osv-scanner.toml can be found on OSV-Scanner repository.`, - //nolint + //nolint:lll Markdown: `Fix the foo by following information from [OSV](https://osv.dev/foo). If the vulnerability is in a dependency, update the dependency to a non-vulnerable version. If no update is available, consider whether to remove the dependency. If you believe the vulnerability does not affect your project, the vulnerability can be ignored. To ignore, create an osv-scanner.toml ([example](https://github.com/google/osv.dev/blob/eb99b02ec8895fe5b87d1e76675ddad79a15f817/vulnfeeds/osv-scanner.toml)) file next to the dependency manifest (e.g. package-lock.json) and specify the ID to ignore and reason. Details on the structure of osv-scanner.toml can be found on [OSV-Scanner repository](https://github.com/google/osv-scanner#ignore-vulnerabilities-by-id).`, diff --git a/probes/packagedWithAutomatedWorkflow/impl.go b/probes/packagedWithAutomatedWorkflow/impl.go index bf261d94f7b..5c30e2766d2 100644 --- a/probes/packagedWithAutomatedWorkflow/impl.go +++ b/probes/packagedWithAutomatedWorkflow/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package packagedWithAutomatedWorkflow import ( diff --git a/probes/packagedWithAutomatedWorkflow/impl_test.go b/probes/packagedWithAutomatedWorkflow/impl_test.go index 0d9e6b38bc2..4f3e06964e6 100644 --- a/probes/packagedWithAutomatedWorkflow/impl_test.go +++ b/probes/packagedWithAutomatedWorkflow/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package packagedWithAutomatedWorkflow import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { msg := "msg" t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/sastToolCodeQLInstalled/impl.go b/probes/sastToolCodeQLInstalled/impl.go index d3f3b656627..dd781d5f22e 100644 --- a/probes/sastToolCodeQLInstalled/impl.go +++ b/probes/sastToolCodeQLInstalled/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package sastToolCodeQLInstalled import ( diff --git a/probes/sastToolCodeQLInstalled/impl_test.go b/probes/sastToolCodeQLInstalled/impl_test.go index 9f47126b076..baf0e407e88 100644 --- a/probes/sastToolCodeQLInstalled/impl_test.go +++ b/probes/sastToolCodeQLInstalled/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package sastToolCodeQLInstalled import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/sastToolRunsOnAllCommits/impl.go b/probes/sastToolRunsOnAllCommits/impl.go index 142cae9ea87..5fcbe9c38cc 100644 --- a/probes/sastToolRunsOnAllCommits/impl.go +++ b/probes/sastToolRunsOnAllCommits/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package sastToolRunsOnAllCommits import ( diff --git a/probes/sastToolRunsOnAllCommits/impl_test.go b/probes/sastToolRunsOnAllCommits/impl_test.go index 09c6e988f48..88f0bbd02b9 100644 --- a/probes/sastToolRunsOnAllCommits/impl_test.go +++ b/probes/sastToolRunsOnAllCommits/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package sastToolRunsOnAllCommits import ( @@ -27,7 +27,6 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/sastToolSonarInstalled/impl.go b/probes/sastToolSonarInstalled/impl.go index 4c68afbeba1..991d94ebb87 100644 --- a/probes/sastToolSonarInstalled/impl.go +++ b/probes/sastToolSonarInstalled/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package sastToolSonarInstalled import ( diff --git a/probes/sastToolSonarInstalled/impl_test.go b/probes/sastToolSonarInstalled/impl_test.go index eeb150f6a1b..2c30a6d2b0f 100644 --- a/probes/sastToolSonarInstalled/impl_test.go +++ b/probes/sastToolSonarInstalled/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package sastToolSonarInstalled import ( @@ -27,7 +27,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/securityPolicyContainsLinks/impl.go b/probes/securityPolicyContainsLinks/impl.go index ebce49efd24..aea3cb5e55d 100644 --- a/probes/securityPolicyContainsLinks/impl.go +++ b/probes/securityPolicyContainsLinks/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyContainsLinks import ( diff --git a/probes/securityPolicyContainsLinks/impl_test.go b/probes/securityPolicyContainsLinks/impl_test.go index 635832b0666..92ff2ce90f6 100644 --- a/probes/securityPolicyContainsLinks/impl_test.go +++ b/probes/securityPolicyContainsLinks/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyContainsLinks import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/securityPolicyContainsText/impl.go b/probes/securityPolicyContainsText/impl.go index d79450682e4..911646592a2 100644 --- a/probes/securityPolicyContainsText/impl.go +++ b/probes/securityPolicyContainsText/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyContainsText import ( diff --git a/probes/securityPolicyContainsText/impl_test.go b/probes/securityPolicyContainsText/impl_test.go index 8ae6e810cbf..f7a4d7154b7 100644 --- a/probes/securityPolicyContainsText/impl_test.go +++ b/probes/securityPolicyContainsText/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyContainsText import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/securityPolicyContainsVulnerabilityDisclosure/impl.go b/probes/securityPolicyContainsVulnerabilityDisclosure/impl.go index f17c2f91acd..2dc9106d90d 100644 --- a/probes/securityPolicyContainsVulnerabilityDisclosure/impl.go +++ b/probes/securityPolicyContainsVulnerabilityDisclosure/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyContainsVulnerabilityDisclosure import ( diff --git a/probes/securityPolicyContainsVulnerabilityDisclosure/impl_test.go b/probes/securityPolicyContainsVulnerabilityDisclosure/impl_test.go index 146125623a7..38d97ff4639 100644 --- a/probes/securityPolicyContainsVulnerabilityDisclosure/impl_test.go +++ b/probes/securityPolicyContainsVulnerabilityDisclosure/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyContainsVulnerabilityDisclosure import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/securityPolicyPresent/impl.go b/probes/securityPolicyPresent/impl.go index bf612dfe3ea..93d414efe83 100644 --- a/probes/securityPolicyPresent/impl.go +++ b/probes/securityPolicyPresent/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyPresent import ( diff --git a/probes/securityPolicyPresent/impl_test.go b/probes/securityPolicyPresent/impl_test.go index 60706348fd5..52cf9217af1 100644 --- a/probes/securityPolicyPresent/impl_test.go +++ b/probes/securityPolicyPresent/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package securityPolicyPresent import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/toolDependabotInstalled/impl.go b/probes/toolDependabotInstalled/impl.go index 3a5028e8774..3d6312e037b 100644 --- a/probes/toolDependabotInstalled/impl.go +++ b/probes/toolDependabotInstalled/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package toolDependabotInstalled import ( diff --git a/probes/toolDependabotInstalled/impl_test.go b/probes/toolDependabotInstalled/impl_test.go index c0573c2b55f..e986eb4cb8e 100644 --- a/probes/toolDependabotInstalled/impl_test.go +++ b/probes/toolDependabotInstalled/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package toolDependabotInstalled import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/toolPyUpInstalled/impl.go b/probes/toolPyUpInstalled/impl.go index 04f8e6acb40..22ff322001b 100644 --- a/probes/toolPyUpInstalled/impl.go +++ b/probes/toolPyUpInstalled/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package toolPyUpInstalled import ( diff --git a/probes/toolPyUpInstalled/impl_test.go b/probes/toolPyUpInstalled/impl_test.go index 40fc498f174..d7f9b5ee6d6 100644 --- a/probes/toolPyUpInstalled/impl_test.go +++ b/probes/toolPyUpInstalled/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package toolPyUpInstalled import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/probes/toolRenovateInstalled/impl.go b/probes/toolRenovateInstalled/impl.go index 219f140f9fa..cbb58cb72a5 100644 --- a/probes/toolRenovateInstalled/impl.go +++ b/probes/toolRenovateInstalled/impl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package toolRenovateInstalled import ( diff --git a/probes/toolRenovateInstalled/impl_test.go b/probes/toolRenovateInstalled/impl_test.go index 8e857655491..a21393becaf 100644 --- a/probes/toolRenovateInstalled/impl_test.go +++ b/probes/toolRenovateInstalled/impl_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:stylecheck +//nolint:stylecheck package toolRenovateInstalled import ( @@ -28,7 +28,7 @@ import ( func Test_Run(t *testing.T) { t.Parallel() - // nolint:govet + //nolint:govet tests := []struct { name string raw *checker.RawResults diff --git a/remediation/remediations.go b/remediation/remediations.go index b5713f7f420..6d49e421280 100644 --- a/remediation/remediations.go +++ b/remediation/remediations.go @@ -29,7 +29,7 @@ var errInvalidArg = errors.New("invalid argument") var ( workflowText = "update your workflow using https://app.stepsecurity.io/secureworkflow/%s/%s/%s?enable=%s" - //nolint + //nolint:lll workflowMarkdown = "update your workflow using [https://app.stepsecurity.io](https://app.stepsecurity.io/secureworkflow/%s/%s/%s?enable=%s)" dockerfilePinText = "pin your Docker image by updating %[1]s to %[1]s@%s" ) diff --git a/rule/rule.go b/rule/rule.go index 1660392465c..f7df3c310fe 100644 --- a/rule/rule.go +++ b/rule/rule.go @@ -49,14 +49,13 @@ type Remediation struct { Effort RemediationEffort `json:"effort"` } -// nolint: govet type jsonRemediation struct { Text []string `yaml:"text"` Markdown []string `yaml:"markdown"` Effort RemediationEffort `yaml:"effort"` } -// nolint: govet +//nolint:govet type jsonRule struct { Short string `yaml:"short"` Desc string `yaml:"desc"` @@ -82,7 +81,7 @@ const ( RiskCritical ) -// nolint: govet +//nolint:govet type Rule struct { Name string Short string @@ -170,7 +169,7 @@ func (r *RemediationEffort) UnmarshalYAML(n *yaml.Node) error { return fmt.Errorf("%w: %w", errInvalid, err) } - // nolint:goconst + //nolint:goconst switch n.Value { case "Low": *r = RemediationEffortLow diff --git a/rule/rule_test.go b/rule/rule_test.go index dbed1155f29..83a6eebdbb4 100644 --- a/rule/rule_test.go +++ b/rule/rule_test.go @@ -34,7 +34,7 @@ var testfs embed.FS func Test_New(t *testing.T) { t.Parallel() - // nolint: govet + //nolint:govet tests := []struct { name string id string diff --git a/utests/utlib.go b/utests/utlib.go index 24b53a1457e..c59c185943a 100644 --- a/utests/utlib.go +++ b/utests/utlib.go @@ -79,7 +79,7 @@ func getTestReturn(cr *checker.CheckResult, logger *TestDetailLogger) (*TestRetu for _, v := range logger.messages { switch v.Type { default: - //nolint: goerr113 + //nolint:goerr113 return nil, fmt.Errorf("invalid type %v", v.Type) case checker.DetailInfo: ret.NumberOfInfo++ @@ -99,7 +99,8 @@ func errCmp(e1, e2 error) bool { } // ValidateTestReturn validates expected TestReturn with actual checker.CheckResult values. -// nolint: thelper +// +//nolint:thelper func ValidateTestReturn( t *testing.T, name string, From be0b915f766ff28de2079e281e5617cac997c53f Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:58:38 +0000 Subject: [PATCH 10/51] :bug: Ignore unpinned dependencies in Dockerfiles in vendored directories (#3675) * :bug: Ignore unpinned dependencies in Dockerfiles in vendored directories Signed-off-by: AdamKorcz * remove unnecessary check Signed-off-by: AdamKorcz --------- Signed-off-by: AdamKorcz --- checks/raw/pinned_dependencies.go | 25 ++++++ checks/raw/pinned_dependencies_test.go | 78 ++++++++++++++++--- .../testdata/vendor/Dockerfile-not-pinned-as | 32 ++++++++ 3 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 checks/raw/testdata/vendor/Dockerfile-not-pinned-as diff --git a/checks/raw/pinned_dependencies.go b/checks/raw/pinned_dependencies.go index 947856bba5f..7a3031e4506 100644 --- a/checks/raw/pinned_dependencies.go +++ b/checks/raw/pinned_dependencies.go @@ -17,6 +17,7 @@ package raw import ( "errors" "fmt" + "path/filepath" "reflect" "regexp" "strings" @@ -111,6 +112,21 @@ func collectDockerfileInsecureDownloads(c *checker.CheckRequest, r *checker.Pinn }, validateDockerfileInsecureDownloads, r) } +func fileIsInVendorDir(pathfn string) bool { + cleanedPath := filepath.Clean(pathfn) + splitCleanedPath := strings.Split(cleanedPath, "/") + + for _, d := range splitCleanedPath { + if strings.EqualFold(d, "vendor") { + return true + } + if strings.EqualFold(d, "third_party") { + return true + } + } + return false +} + var validateDockerfileInsecureDownloads fileparser.DoWhileTrueOnFileContent = func( pathfn string, content []byte, @@ -122,6 +138,10 @@ var validateDockerfileInsecureDownloads fileparser.DoWhileTrueOnFileContent = fu len(args), errInvalidArgLength) } + if fileIsInVendorDir(pathfn) { + return true, nil + } + pdata := dataAsPinnedDependenciesPointer(args[0]) // Return early if this is not a docker file. @@ -219,6 +239,11 @@ var validateDockerfilesPinning fileparser.DoWhileTrueOnFileContent = func( return false, fmt.Errorf( "validateDockerfilesPinning requires exactly 2 arguments: got %v: %w", len(args), errInvalidArgLength) } + + if fileIsInVendorDir(pathfn) { + return true, nil + } + pdata := dataAsPinnedDependenciesPointer(args[0]) // Return early if this is not a dockerfile. diff --git a/checks/raw/pinned_dependencies_test.go b/checks/raw/pinned_dependencies_test.go index 02d8a17e6c0..bc755c8dba1 100644 --- a/checks/raw/pinned_dependencies_test.go +++ b/checks/raw/pinned_dependencies_test.go @@ -340,41 +340,46 @@ func TestDockerfilePinning(t *testing.T) { }{ { name: "invalid dockerfile", - filename: "./testdata/Dockerfile-invalid", + filename: "Dockerfile-invalid", }, { name: "invalid dockerfile sh", - filename: "../testdata/script-sh", + filename: "../../testdata/script-sh", }, { name: "empty file", - filename: "./testdata/Dockerfile-empty", + filename: "Dockerfile-empty", }, { name: "comments only", - filename: "./testdata/Dockerfile-comments", + filename: "Dockerfile-comments", }, { name: "Pinned dockerfile", - filename: "./testdata/Dockerfile-pinned", + filename: "Dockerfile-pinned", }, { name: "Pinned dockerfile as", - filename: "./testdata/Dockerfile-pinned-as", + filename: "Dockerfile-pinned-as", }, { name: "Non-pinned dockerfile as", - filename: "./testdata/Dockerfile-not-pinned-as", + filename: "Dockerfile-not-pinned-as", warns: 2, }, + { + name: "Non-pinned dockerfile but in vendor, ie: 0 warns", + filename: "vendor/Dockerfile-not-pinned-as", + warns: 0, + }, { name: "Non-pinned dockerfile", - filename: "./testdata/Dockerfile-not-pinned", + filename: "Dockerfile-not-pinned", warns: 1, }, { name: "Parser error doesn't affect docker image pinning", - filename: "./testdata/Dockerfile-not-pinned-with-parser-error", + filename: "Dockerfile-not-pinned-with-parser-error", warns: 1, }, } @@ -387,14 +392,14 @@ func TestDockerfilePinning(t *testing.T) { if tt.filename == "" { content = make([]byte, 0) } else { - content, err = os.ReadFile(tt.filename) + content, err = os.ReadFile(filepath.Join("testdata", tt.filename)) if err != nil { t.Errorf("cannot read file: %v", err) } } var r checker.PinningDependenciesData - _, err = validateDockerfilesPinning(tt.filename, content, &r) + _, err = validateDockerfilesPinning(filepath.Join("testdata", tt.filename), content, &r) if !errCmp(err, tt.err) { t.Errorf(cmp.Diff(err, tt.err, cmpopts.EquateErrors())) } @@ -412,6 +417,57 @@ func TestDockerfilePinning(t *testing.T) { } } +func TestFileIsInVendorDir(t *testing.T) { + t.Parallel() + tests := []struct { + name string + filename string + expected bool + }{ + { + name: "not in vendor or third_party", + filename: "a/b/c/d/Dockerfile", + expected: false, + }, + { + name: "is third_party deep in tree", + filename: "a/b/third_party/Dockerfile", + expected: true, + }, + { + name: "in vendor", + filename: "vendor/a/b/Dockerfile", + expected: true, + }, + { + name: "in third_party", + filename: "third_party/b/c/Dockerfile", + expected: true, + }, + { + name: "in deep vendor", + filename: "a/b/c/vendor/Dockerfile", + expected: true, + }, + { + name: "misspelled vendor dir", + filename: "a/vendorr/Dockerfile", + expected: false, + }, + } + + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := fileIsInVendorDir(tt.filename) + if got != tt.expected { + t.Errorf("expected %v. Got %v", tt.expected, got) + } + }) + } +} + func TestDockerfilePinningFromLineNumber(t *testing.T) { t.Parallel() tests := []struct { diff --git a/checks/raw/testdata/vendor/Dockerfile-not-pinned-as b/checks/raw/testdata/vendor/Dockerfile-not-pinned-as new file mode 100644 index 00000000000..81313041d47 --- /dev/null +++ b/checks/raw/testdata/vendor/Dockerfile-not-pinned-as @@ -0,0 +1,32 @@ + +# Copyright 2021 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. +FROM python:3.7@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2 as base + +FROM python:3.7 as build +ARG TARGETOS +ARG TARGETARCH +RUN CGO_ENABLED=0 make build-scorecard + +# Add spaces + FROM build +RUN /hello-world + +FROM base as base2 +RUN ls + +FROM base2 +RUN ls + +FROM python@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2 \ No newline at end of file From 1c3d9eb6e79a0aa246a787bacc287001795b6633 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:57:10 +0000 Subject: [PATCH 11/51] :seedling: Migrate Maintained check to probes (#3507) * :seedling: Migrate Maintained check to probes Signed-off-by: AdamKorcz * fix typos Signed-off-by: AdamKorcz * rename 'archived' probe to 'notArchvied Signed-off-by: AdamKorcz * remove part of comment Signed-off-by: AdamKorcz * fix typo Signed-off-by: AdamKorcz * log negative findings Signed-off-by: AdamKorcz * log non positive findings if repo was created less than 90 days ago Signed-off-by: AdamKorcz * rename probe from 'activityOnIssuesByCollaboratorsMembersOrOwnersInLast90Days' to 'issueActivityByProjectMember' Signed-off-by: AdamKorcz * change probe descriptions Signed-off-by: AdamKorcz * rename 'wasCreatedInLast90Days' probe to 'notCreatedInLast90Days' Signed-off-by: AdamKorcz * Add tests with zero issues Signed-off-by: AdamKorcz * use values instead of returning multiple findings Signed-off-by: AdamKorcz * return negative findings instead of non-positive Signed-off-by: AdamKorcz * correct 'notCreatedInLast90Days' probe definition Signed-off-by: AdamKorcz * make nested conditionals a single line Signed-off-by: AdamKorcz * make nested conditionals a single line Signed-off-by: AdamKorcz * change var name 'issuesUpdatedWithinThreshold' to 'numberOfIssuesUpdatedWithinThreshold' Signed-off-by: AdamKorcz * rename 'notCreatedInLast90Days' to 'notCreatedRecently' Signed-off-by: AdamKorcz * explain 'commitsWithinThreshold' in probe definition Signed-off-by: AdamKorcz * rename 'commitsInLast90Days' to 'hasRecentCommits'" -s Signed-off-by: AdamKorcz * fix linter issues Signed-off-by: AdamKorcz * define 'numberOfIssuesUpdatedWithinThreshold' Signed-off-by: AdamKorcz --------- Signed-off-by: AdamKorcz --- checks/evaluation/maintained.go | 98 +++---- checks/evaluation/maintained_test.go | 265 ++++++------------ checks/maintained.go | 15 +- probes/entries.go | 10 + probes/hasRecentCommits/def.yml | 27 ++ probes/hasRecentCommits/impl.go | 78 ++++++ probes/hasRecentCommits/impl_test.go | 130 +++++++++ probes/issueActivityByProjectMember/def.yml | 27 ++ probes/issueActivityByProjectMember/impl.go | 100 +++++++ .../issueActivityByProjectMember/impl_test.go | 235 ++++++++++++++++ probes/notArchived/def.yml | 27 ++ probes/notArchived/impl.go | 63 +++++ probes/notArchived/impl_test.go | 91 ++++++ probes/notCreatedRecently/def.yml | 27 ++ probes/notCreatedRecently/impl.go | 73 +++++ probes/notCreatedRecently/impl_test.go | 88 ++++++ 16 files changed, 1120 insertions(+), 234 deletions(-) create mode 100644 probes/hasRecentCommits/def.yml create mode 100644 probes/hasRecentCommits/impl.go create mode 100644 probes/hasRecentCommits/impl_test.go create mode 100644 probes/issueActivityByProjectMember/def.yml create mode 100644 probes/issueActivityByProjectMember/impl.go create mode 100644 probes/issueActivityByProjectMember/impl_test.go create mode 100644 probes/notArchived/def.yml create mode 100644 probes/notArchived/impl.go create mode 100644 probes/notArchived/impl_test.go create mode 100644 probes/notCreatedRecently/def.yml create mode 100644 probes/notCreatedRecently/impl.go create mode 100644 probes/notCreatedRecently/impl_test.go diff --git a/checks/evaluation/maintained.go b/checks/evaluation/maintained.go index a4fd2bfc66d..bf4daeee897 100644 --- a/checks/evaluation/maintained.go +++ b/checks/evaluation/maintained.go @@ -16,11 +16,14 @@ package evaluation import ( "fmt" - "time" "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" sce "github.com/ossf/scorecard/v4/errors" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/hasRecentCommits" + "github.com/ossf/scorecard/v4/probes/issueActivityByProjectMember" + "github.com/ossf/scorecard/v4/probes/notArchived" + "github.com/ossf/scorecard/v4/probes/notCreatedRecently" ) const ( @@ -30,68 +33,67 @@ const ( ) // Maintained applies the score policy for the Maintained check. -func Maintained(name string, dl checker.DetailLogger, r *checker.MaintainedData) checker.CheckResult { - if r == nil { - e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") - return checker.CreateRuntimeErrorResult(name, e) +func Maintained(name string, + findings []finding.Finding, dl checker.DetailLogger, +) checker.CheckResult { + // We have 4 unique probes, each should have a finding. + expectedProbes := []string{ + notArchived.Probe, + issueActivityByProjectMember.Probe, + hasRecentCommits.Probe, + notCreatedRecently.Probe, } - if r.ArchivedStatus.Status { - return checker.CreateMinScoreResult(name, "repo is marked as archived") + if !finding.UniqueProbesEqual(findings, expectedProbes) { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results") + return checker.CreateRuntimeErrorResult(name, e) } - // If not explicitly marked archived, look for activity in past `lookBackDays`. - threshold := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*lookBackDays /*days*/) - commitsWithinThreshold := 0 - for i := range r.DefaultBranchCommits { - if r.DefaultBranchCommits[i].CommittedDate.After(threshold) { - commitsWithinThreshold++ - } + if projectIsArchived(findings) { + checker.LogFindings(negativeFindings(findings), dl) + return checker.CreateMinScoreResult(name, "project is archived") } - // Emit a warning if this repo was created recently - recencyThreshold := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*lookBackDays /*days*/) - if r.CreatedAt.After(recencyThreshold) { - dl.Warn(&checker.LogMessage{ - Text: fmt.Sprintf("repo was created in the last %d days (Created at: %s), please review its contents carefully", - lookBackDays, r.CreatedAt.Format(time.RFC3339)), - }) - daysSinceRepoCreated := int(time.Since(r.CreatedAt).Hours() / 24) - return checker.CreateMinScoreResult(name, - fmt.Sprintf("repo was created %d days ago, not enough maintenance history", daysSinceRepoCreated), - ) + if projectWasCreatedInLast90Days(findings) { + checker.LogFindings(negativeFindings(findings), dl) + return checker.CreateMinScoreResult(name, "project was created in last 90 days. please review its contents carefully") } - issuesUpdatedWithinThreshold := 0 - for i := range r.Issues { - if hasActivityByCollaboratorOrHigher(&r.Issues[i], threshold) { - issuesUpdatedWithinThreshold++ + commitsWithinThreshold := 0 + numberOfIssuesUpdatedWithinThreshold := 0 + + for i := range findings { + f := &findings[i] + if f.Outcome == finding.OutcomePositive { + switch f.Probe { + case issueActivityByProjectMember.Probe: + numberOfIssuesUpdatedWithinThreshold = f.Values["numberOfIssuesUpdatedWithinThreshold"] + case hasRecentCommits.Probe: + commitsWithinThreshold = f.Values["commitsWithinThreshold"] + } } } return checker.CreateProportionalScoreResult(name, fmt.Sprintf( - "%d commit(s) out of %d and %d issue activity out of %d found in the last %d days", - commitsWithinThreshold, len(r.DefaultBranchCommits), issuesUpdatedWithinThreshold, len(r.Issues), lookBackDays), - commitsWithinThreshold+issuesUpdatedWithinThreshold, activityPerWeek*lookBackDays/daysInOneWeek) + "%d commit(s) and %d issue activity found in the last %d days", + commitsWithinThreshold, numberOfIssuesUpdatedWithinThreshold, lookBackDays), + commitsWithinThreshold+numberOfIssuesUpdatedWithinThreshold, activityPerWeek*lookBackDays/daysInOneWeek) } -// hasActivityByCollaboratorOrHigher returns true if the issue was created or commented on by an -// owner/collaborator/member since the threshold. -func hasActivityByCollaboratorOrHigher(issue *clients.Issue, threshold time.Time) bool { - if issue == nil { - return false +func projectIsArchived(findings []finding.Finding) bool { + for i := range findings { + f := &findings[i] + if f.Outcome == finding.OutcomeNegative && f.Probe == notArchived.Probe { + return true + } } + return false +} - if issue.AuthorAssociation.Gte(clients.RepoAssociationCollaborator) && - issue.CreatedAt != nil && issue.CreatedAt.After(threshold) { - // The creator of the issue is a collaborator or higher. - return true - } - for _, comment := range issue.Comments { - if comment.AuthorAssociation.Gte(clients.RepoAssociationCollaborator) && - comment.CreatedAt != nil && - comment.CreatedAt.After(threshold) { - // The author of the comment is a collaborator or higher. +func projectWasCreatedInLast90Days(findings []finding.Finding) bool { + for i := range findings { + f := &findings[i] + if f.Outcome == finding.OutcomeNegative && f.Probe == notCreatedRecently.Probe { return true } } diff --git a/checks/evaluation/maintained_test.go b/checks/evaluation/maintained_test.go index 5170691560c..420955e5cd1 100644 --- a/checks/evaluation/maintained_test.go +++ b/checks/evaluation/maintained_test.go @@ -15,221 +15,120 @@ package evaluation import ( "testing" - "time" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" + sce "github.com/ossf/scorecard/v4/errors" + "github.com/ossf/scorecard/v4/finding" scut "github.com/ossf/scorecard/v4/utests" ) -func Test_hasActivityByCollaboratorOrHigher(t *testing.T) { - t.Parallel() - r := clients.RepoAssociationCollaborator - twentDaysAgo := time.Now().AddDate(0 /*years*/, 0 /*months*/, -20 /*days*/) - type args struct { - issue *clients.Issue - threshold time.Time - } - tests := []struct { //nolint:govet - name string - args args - want bool - }{ - { - name: "nil issue", - args: args{ - issue: nil, - threshold: time.Now(), - }, - want: false, - }, - { - name: "repo-association collaborator", - args: args{ - issue: &clients.Issue{ - CreatedAt: nil, - AuthorAssociation: &r, - }, - }, - want: false, - }, - { - name: "twentyDaysAgo", - args: args{ - issue: &clients.Issue{ - CreatedAt: &twentDaysAgo, - AuthorAssociation: &r, - }, - }, - want: true, - }, - { - name: "repo-association collaborator with comment", - args: args{ - issue: &clients.Issue{ - CreatedAt: nil, - AuthorAssociation: &r, - Comments: []clients.IssueComment{ - { - CreatedAt: &twentDaysAgo, - AuthorAssociation: &r, - }, - }, - }, - }, - want: true, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - if got := hasActivityByCollaboratorOrHigher(tt.args.issue, tt.args.threshold); got != tt.want { - t.Errorf("hasActivityByCollaboratorOrHigher() = %v, want %v", got, tt.want) - } - }) - } -} - func TestMaintained(t *testing.T) { - twentyDaysAgo := time.Now().AddDate(0 /*years*/, 0 /*months*/, -20 /*days*/) - collab := clients.RepoAssociationCollaborator t.Parallel() - type args struct { //nolint:govet - name string - dl checker.DetailLogger - r *checker.MaintainedData - } tests := []struct { - name string - args args - want checker.CheckResult + name string + findings []finding.Finding + result scut.TestReturn }{ { - name: "nil", - args: args{ - name: "test", - dl: nil, - r: nil, - }, - want: checker.CheckResult{ - Name: "test", - Version: 2, - Reason: "internal error: empty raw data", - Score: -1, - }, - }, - { - name: "archived", - args: args{ - name: "test", - dl: nil, - r: &checker.MaintainedData{ - ArchivedStatus: checker.ArchivedStatus{Status: true}, + name: "Two commits in last 90 days", + findings: []finding.Finding{ + { + Probe: "hasRecentCommits", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + "commitsWithinThreshold": 2, + }, + }, { + Probe: "issueActivityByProjectMember", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + "numberOfIssuesUpdatedWithinThreshold": 1, + }, + }, { + Probe: "notArchived", + Outcome: finding.OutcomePositive, + }, { + Probe: "notCreatedRecently", + Outcome: finding.OutcomePositive, }, }, - want: checker.CheckResult{ - Name: "test", - Version: 2, - Reason: "repo is marked as archived", - Score: 0, + result: scut.TestReturn{ + Score: 2, }, }, { - name: "no activity", - args: args{ - name: "test", - dl: nil, - r: &checker.MaintainedData{ - ArchivedStatus: checker.ArchivedStatus{Status: false}, - DefaultBranchCommits: []clients.Commit{ - { - CommittedDate: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), - }, - }, + name: "No issues, no commits and not archived", + findings: []finding.Finding{ + { + Probe: "hasRecentCommits", + Outcome: finding.OutcomeNegative, + }, { + Probe: "issueActivityByProjectMember", + Outcome: finding.OutcomeNegative, + }, { + Probe: "notArchived", + Outcome: finding.OutcomePositive, + }, { + Probe: "notCreatedRecently", + Outcome: finding.OutcomePositive, }, }, - want: checker.CheckResult{ - Name: "test", - Version: 2, - Reason: "0 commit(s) out of 1 and 0 issue activity out of 0 found in the last 90 days -- score normalized to 0", - Score: 0, + result: scut.TestReturn{ + Score: 0, }, }, { - name: "commit activity in the last 30 days", - args: args{ - name: "test", - dl: &scut.TestDetailLogger{}, - r: &checker.MaintainedData{ - ArchivedStatus: checker.ArchivedStatus{Status: false}, - DefaultBranchCommits: []clients.Commit{ - { - CommittedDate: time.Now().AddDate(0 /*years*/, 0 /*months*/, -20 /*days*/), - }, - { - CommittedDate: time.Now().AddDate(0 /*years*/, 0 /*months*/, -10 /*days*/), - }, - }, - - Issues: []clients.Issue{ - { - CreatedAt: &twentyDaysAgo, - AuthorAssociation: &collab, - }, - }, - CreatedAt: time.Now().AddDate(0 /*years*/, 0 /*months*/, -100 /*days*/), + name: "Wrong probe name", + findings: []finding.Finding{ + { + Probe: "hasRecentCommits", + Outcome: finding.OutcomeNegative, + }, { + Probe: "issueActivityByProjectMember", + Outcome: finding.OutcomeNegative, + }, { + Probe: "archvied", /*misspelling*/ + Outcome: finding.OutcomePositive, + }, { + Probe: "notCreatedRecently", + Outcome: finding.OutcomePositive, }, }, - want: checker.CheckResult{ - Name: "test", - Version: 2, - Reason: "2 commit(s) out of 2 and 1 issue activity out of 1 found in the last 90 days -- score normalized to 2", - Score: 2, + result: scut.TestReturn{ + Score: -1, + Error: sce.ErrScorecardInternal, }, }, { - name: "Repo created recently", - args: args{ - name: "test", - dl: &scut.TestDetailLogger{}, - r: &checker.MaintainedData{ - ArchivedStatus: checker.ArchivedStatus{Status: false}, - DefaultBranchCommits: []clients.Commit{ - { - CommittedDate: time.Now().AddDate(0 /*years*/, 0 /*months*/, -20 /*days*/), - }, - { - CommittedDate: time.Now().AddDate(0 /*years*/, 0 /*months*/, -10 /*days*/), - }, - }, - - Issues: []clients.Issue{ - { - CreatedAt: &twentyDaysAgo, - AuthorAssociation: &collab, - }, - }, - CreatedAt: time.Now().AddDate(0 /*years*/, 0 /*months*/, -10 /*days*/), + name: "Project is archived", + findings: []finding.Finding{ + { + Probe: "hasRecentCommits", + Outcome: finding.OutcomeNegative, + }, { + Probe: "issueActivityByProjectMember", + Outcome: finding.OutcomeNegative, + }, { + Probe: "notArchived", + Outcome: finding.OutcomeNegative, + }, { + Probe: "notCreatedRecently", + Outcome: finding.OutcomePositive, }, }, - want: checker.CheckResult{ - Name: "test", - Version: 2, - Reason: "repo was created 10 days ago, not enough maintenance history", - Score: 0, + result: scut.TestReturn{ + Score: 0, + NumberOfWarn: 3, }, }, } for _, tt := range tests { - tt := tt + tt := tt // Parallel testing t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := Maintained(tt.args.name, tt.args.dl, tt.args.r); !cmp.Equal(got, tt.want, cmpopts.IgnoreFields(checker.CheckResult{}, "Error")) { //nolint:lll - t.Errorf("Maintained() = %v, want %v", got, cmp.Diff(got, tt.want, cmpopts.IgnoreFields(checker.CheckResult{}, "Error"))) //nolint:lll + dl := scut.TestDetailLogger{} + got := Maintained(tt.name, tt.findings, &dl) + if !scut.ValidateTestReturn(t, tt.name, &tt.result, &got, &dl) { + t.Errorf("got %v, expected %v", got, tt.result) } }) } diff --git a/checks/maintained.go b/checks/maintained.go index ec653d6a20e..d94e6978d30 100644 --- a/checks/maintained.go +++ b/checks/maintained.go @@ -19,6 +19,8 @@ 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" + "github.com/ossf/scorecard/v4/probes/zrunner" ) // CheckMaintained is the exported check name for Maintained. @@ -41,9 +43,16 @@ func Maintained(c *checker.CheckRequest) checker.CheckResult { } // Set the raw results. - if c.RawResults != nil { - c.RawResults.MaintainedResults = rawData + pRawResults := getRawResults(c) + pRawResults.MaintainedResults = rawData + + // Evaluate the probes. + findings, err := zrunner.Run(pRawResults, probes.Maintained) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckMaintained, e) } - return evaluation.Maintained(CheckMaintained, c.Dlogger, &rawData) + // Return the score evaluation. + return evaluation.Maintained(CheckMaintained, findings, c.Dlogger) } diff --git a/probes/entries.go b/probes/entries.go index daec6474ce6..f745fb7512c 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -36,6 +36,10 @@ import ( "github.com/ossf/scorecard/v4/probes/hasLicenseFile" "github.com/ossf/scorecard/v4/probes/hasLicenseFileAtTopDir" "github.com/ossf/scorecard/v4/probes/hasOSVVulnerabilities" + "github.com/ossf/scorecard/v4/probes/hasRecentCommits" + "github.com/ossf/scorecard/v4/probes/issueActivityByProjectMember" + "github.com/ossf/scorecard/v4/probes/notArchived" + "github.com/ossf/scorecard/v4/probes/notCreatedRecently" "github.com/ossf/scorecard/v4/probes/packagedWithAutomatedWorkflow" "github.com/ossf/scorecard/v4/probes/sastToolCodeQLInstalled" "github.com/ossf/scorecard/v4/probes/sastToolRunsOnAllCommits" @@ -107,6 +111,12 @@ var ( hasDangerousWorkflowScriptInjection.Run, hasDangerousWorkflowUntrustedCheckout.Run, } + Maintained = []ProbeImpl{ + notArchived.Run, + hasRecentCommits.Run, + issueActivityByProjectMember.Run, + notCreatedRecently.Run, + } ) //nolint:gochecknoinits diff --git a/probes/hasRecentCommits/def.yml b/probes/hasRecentCommits/def.yml new file mode 100644 index 00000000000..95b243cea2e --- /dev/null +++ b/probes/hasRecentCommits/def.yml @@ -0,0 +1,27 @@ +# 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: hasRecentCommits +short: Check whether the project has at least one commit per week over the last 90 days. +motivation: > + A project which is not active might not be patched, have its dependencies patched, or be actively tested and used. However, a lack of active maintenance is not necessarily always a problem. Some software, especially smaller utility functions, does not normally need to be maintained. For example, a library that determines if an integer is even would not normally need maintenance unless an underlying implementation language definition changed. A lack of active maintenance should signal that potential users should investigate further to judge the situation. A project may not need further features or maintenance; In this case, the probe results can be disregarded. +implementation: > + The implementation checks the number of commits made in the last 90 days by any user type. +outcome: + - If the project has commits from the last 90 days, the probe returns one OutcomePositive with a "commitsWithinThreshold" value which contains the number of commits that the probe found within the threshold. The probe will also return a "lookBackDays" value which is the number of days that the probe includes in its threshold - which is 90. + - If the project does not have commits in the last 90 days, the probe returns a single OutcomeNegative. +remediation: + effort: Low + text: + - The only way to remediate this probe is to make contributions to the project, however, some projects have reached a level of maturity that does require further contributions. diff --git a/probes/hasRecentCommits/impl.go b/probes/hasRecentCommits/impl.go new file mode 100644 index 00000000000..fbd3abbd28e --- /dev/null +++ b/probes/hasRecentCommits/impl.go @@ -0,0 +1,78 @@ +// 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. + +//nolint:stylecheck +package hasRecentCommits + +import ( + "embed" + "fmt" + "time" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + lookBackDays = 90 +) + +const Probe = "hasRecentCommits" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + var findings []finding.Finding + + r := raw.MaintainedResults + threshold := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*lookBackDays /*days*/) + commitsWithinThreshold := 0 + + for i := range r.DefaultBranchCommits { + commit := r.DefaultBranchCommits[i] + if commit.CommittedDate.After(threshold) { + commitsWithinThreshold++ + } + } + + if commitsWithinThreshold > 0 { + f, err := finding.NewWith(fs, Probe, + "Found a contribution within the threshold.", nil, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithValues(map[string]int{ + "commitsWithinThreshold": commitsWithinThreshold, + "lookBackDays": 90, + }) + findings = append(findings, *f) + } else { + f, err := finding.NewWith(fs, Probe, + "Did not find contribution within the threshold.", nil, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + + return findings, Probe, nil +} diff --git a/probes/hasRecentCommits/impl_test.go b/probes/hasRecentCommits/impl_test.go new file mode 100644 index 00000000000..e603e6e7e21 --- /dev/null +++ b/probes/hasRecentCommits/impl_test.go @@ -0,0 +1,130 @@ +// 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. + +//nolint:stylecheck +package hasRecentCommits + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" +) + +func fiveCommitsInThreshold() []clients.Commit { + fiveCommitsInThreshold := make([]clients.Commit, 0) + for i := 0; i < 5; i++ { + commit := clients.Commit{ + CommittedDate: time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*i /*days*/), + } + fiveCommitsInThreshold = append(fiveCommitsInThreshold, commit) + } + return fiveCommitsInThreshold +} + +func twentyCommitsInThresholdAndtwentyNot() []clients.Commit { + twentyCommitsInThresholdAndtwentyNot := make([]clients.Commit, 0) + for i := 70; i < 111; i++ { + commit := clients.Commit{ + CommittedDate: time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*i /*days*/), + } + twentyCommitsInThresholdAndtwentyNot = append(twentyCommitsInThresholdAndtwentyNot, commit) + } + return twentyCommitsInThresholdAndtwentyNot +} + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + values map[string]int + err error + }{ + { + name: "Has no issues in threshold", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + Issues: []clients.Issue{}, + }, + }, + outcomes: []finding.Outcome{finding.OutcomeNegative}, + }, + { + name: "Has five commits in threshold", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + DefaultBranchCommits: fiveCommitsInThreshold(), + }, + }, + values: map[string]int{ + "commitsWithinThreshold": 5, + "lookBackDays": 90, + }, + outcomes: []finding.Outcome{finding.OutcomePositive}, + }, + { + name: "Has twenty in threshold", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + DefaultBranchCommits: twentyCommitsInThresholdAndtwentyNot(), + }, + }, + values: map[string]int{ + "commitsWithinThreshold": 20, + "lookBackDays": 90, + }, + outcomes: []finding.Outcome{finding.OutcomePositive}, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range findings { + outcome := &tt.outcomes[i] + f := &findings[i] + if tt.values != nil { + if diff := cmp.Diff(tt.values, f.Values); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} diff --git a/probes/issueActivityByProjectMember/def.yml b/probes/issueActivityByProjectMember/def.yml new file mode 100644 index 00000000000..d1ff0475989 --- /dev/null +++ b/probes/issueActivityByProjectMember/def.yml @@ -0,0 +1,27 @@ +# 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: issueActivityByProjectMember +short: Checks that a collaborator, member or owner has participated in issues in the last 90 days. +motivation: > + A project which is not active might not be patched, have its dependencies patched, or be actively tested and used. However, a lack of active maintenance is not necessarily always a problem. Some software, especially smaller utility functions, does not normally need to be maintained. For example, a library that determines if an integer is even would not normally need maintenance unless an underlying implementation language definition changed. A lack of active maintenance should signal that potential users should investigate further to judge the situation. +implementation: > + The probe checks whether collaborators, members or owners of a project have participated in issues in the last 90 days. +outcome: + - If collaborators, members or owners have participated in issues in the last 90 days, the probe returns one OutcomePositive. The probe also returns a "numberOfIssuesUpdatedWithinThreshold" value with represents the number of issues on the repository which project collaborators, members or owners have shown activity in. + - If collaborators, members or owners have NOT participated in issues in the last 90 days, the probe returns a single OutcomeNegative. +remediation: + effort: High + text: + - It is not possible for users of a project to affect the issue activity of collaborators, members or owners of a project. diff --git a/probes/issueActivityByProjectMember/impl.go b/probes/issueActivityByProjectMember/impl.go new file mode 100644 index 00000000000..493c075ac74 --- /dev/null +++ b/probes/issueActivityByProjectMember/impl.go @@ -0,0 +1,100 @@ +// 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. + +//nolint:stylecheck +package issueActivityByProjectMember + +import ( + "embed" + "fmt" + "time" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + lookBackDays = 90 +) + +const Probe = "issueActivityByProjectMember" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.MaintainedResults + numberOfIssuesUpdatedWithinThreshold := 0 + + // Look for activity in past `lookBackDays`. + threshold := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*lookBackDays /*days*/) + var findings []finding.Finding + for i := range r.Issues { + if hasActivityByCollaboratorOrHigher(&r.Issues[i], threshold) { + numberOfIssuesUpdatedWithinThreshold++ + } + } + + if numberOfIssuesUpdatedWithinThreshold > 0 { + f, err := finding.NewWith(fs, Probe, + "Found a issue within the threshold.", nil, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithValues(map[string]int{ + "numberOfIssuesUpdatedWithinThreshold": numberOfIssuesUpdatedWithinThreshold, + }) + findings = append(findings, *f) + } else { + f, err := finding.NewWith(fs, Probe, + "Did not find issues within the threshold.", nil, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + + return findings, Probe, nil +} + +// hasActivityByCollaboratorOrHigher returns true if the issue was created or commented on by an +// owner/collaborator/member since the threshold. +func hasActivityByCollaboratorOrHigher(issue *clients.Issue, threshold time.Time) bool { + if issue == nil { + return false + } + + if issue.AuthorAssociation.Gte(clients.RepoAssociationCollaborator) && + issue.CreatedAt != nil && issue.CreatedAt.After(threshold) { + // The creator of the issue is a collaborator or higher. + return true + } + for _, comment := range issue.Comments { + if comment.AuthorAssociation.Gte(clients.RepoAssociationCollaborator) && + comment.CreatedAt != nil && + comment.CreatedAt.After(threshold) { + // The author of the comment is a collaborator or higher. + return true + } + } + return false +} diff --git a/probes/issueActivityByProjectMember/impl_test.go b/probes/issueActivityByProjectMember/impl_test.go new file mode 100644 index 00000000000..9f750671b3c --- /dev/null +++ b/probes/issueActivityByProjectMember/impl_test.go @@ -0,0 +1,235 @@ +// 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. + +//nolint:stylecheck +package issueActivityByProjectMember + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" +) + +var ( + collab = clients.RepoAssociationCollaborator + firstTimeUser = clients.RepoAssociationFirstTimeContributor +) + +func fiveIssuesInThreshold() []clients.Issue { + fiveIssuesInThreshold := make([]clients.Issue, 0) + for i := 0; i < 5; i++ { + createdAt := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*i /*days*/) + commit := clients.Issue{ + CreatedAt: &createdAt, + AuthorAssociation: &collab, + } + fiveIssuesInThreshold = append(fiveIssuesInThreshold, commit) + } + return fiveIssuesInThreshold +} + +func fiveInThresholdByCollabAndFiveByFirstTimeUser() []clients.Issue { + fiveInThresholdByCollabAndFiveByFirstTimeUser := make([]clients.Issue, 0) + for i := 0; i < 10; i++ { + createdAt := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*i /*days*/) + commit := clients.Issue{ + CreatedAt: &createdAt, + } + if i > 4 { + commit.AuthorAssociation = &collab + } else { + commit.AuthorAssociation = &firstTimeUser + } + fiveInThresholdByCollabAndFiveByFirstTimeUser = append(fiveInThresholdByCollabAndFiveByFirstTimeUser, commit) + } + return fiveInThresholdByCollabAndFiveByFirstTimeUser +} + +func twentyIssuesInThresholdAndtwentyNot() []clients.Issue { + twentyIssuesInThresholdAndtwentyNot := make([]clients.Issue, 0) + for i := 70; i < 111; i++ { + createdAt := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*i /*days*/) + commit := clients.Issue{ + CreatedAt: &createdAt, + AuthorAssociation: &collab, + } + twentyIssuesInThresholdAndtwentyNot = append(twentyIssuesInThresholdAndtwentyNot, commit) + } + return twentyIssuesInThresholdAndtwentyNot +} + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + values map[string]int + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "Has no issues in threshold", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + Issues: []clients.Issue{}, + }, + }, + outcomes: []finding.Outcome{finding.OutcomeNegative}, + }, + { + name: "Has 5 issues in threshold", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + Issues: fiveIssuesInThreshold(), + }, + }, + values: map[string]int{ + "numberOfIssuesUpdatedWithinThreshold": 5, + }, + outcomes: []finding.Outcome{finding.OutcomePositive}, + }, + { + name: "Has 20 issues in threshold", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + Issues: twentyIssuesInThresholdAndtwentyNot(), + }, + }, + values: map[string]int{ + "numberOfIssuesUpdatedWithinThreshold": 20, + }, + outcomes: []finding.Outcome{finding.OutcomePositive}, + }, + { + name: "Has 5 issues by collaborator and 5 by first time user", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + Issues: fiveInThresholdByCollabAndFiveByFirstTimeUser(), + }, + }, + values: map[string]int{ + "numberOfIssuesUpdatedWithinThreshold": 5, + }, + outcomes: []finding.Outcome{finding.OutcomePositive}, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range findings { + outcome := &tt.outcomes[i] + f := &findings[i] + if tt.values != nil { + if diff := cmp.Diff(tt.values, f.Values); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} + +func Test_hasActivityByCollaboratorOrHigher(t *testing.T) { + t.Parallel() + r := clients.RepoAssociationCollaborator + twentDaysAgo := time.Now().AddDate(0 /*years*/, 0 /*months*/, -20 /*days*/) + type args struct { + issue *clients.Issue + threshold time.Time + } + tests := []struct { //nolint:govet + name string + args args + want bool + }{ + { + name: "nil issue", + args: args{ + issue: nil, + threshold: time.Now(), + }, + want: false, + }, + { + name: "repo-association collaborator", + args: args{ + issue: &clients.Issue{ + CreatedAt: nil, + AuthorAssociation: &r, + }, + }, + want: false, + }, + { + name: "twentyDaysAgo", + args: args{ + issue: &clients.Issue{ + CreatedAt: &twentDaysAgo, + AuthorAssociation: &r, + }, + }, + want: true, + }, + { + name: "repo-association collaborator with comment", + args: args{ + issue: &clients.Issue{ + CreatedAt: nil, + AuthorAssociation: &r, + Comments: []clients.IssueComment{ + { + CreatedAt: &twentDaysAgo, + AuthorAssociation: &r, + }, + }, + }, + }, + want: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := hasActivityByCollaboratorOrHigher(tt.args.issue, tt.args.threshold); got != tt.want { + t.Errorf("hasActivityByCollaboratorOrHigher() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/probes/notArchived/def.yml b/probes/notArchived/def.yml new file mode 100644 index 00000000000..b5858c1388f --- /dev/null +++ b/probes/notArchived/def.yml @@ -0,0 +1,27 @@ +# 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: notArchived +short: Check that the project is archvied +motivation: > + A project which is not active might not be patched, have its dependencies patched, or be actively tested and used. However, a lack of active maintenance is not necessarily always a problem. Some software, especially smaller utility functions, does not normally need to be maintained. For example, a library that determines if an integer is even would not normally need maintenance unless an underlying implementation language definition changed. A lack of active maintenance should signal that potential users should investigate further to judge the situation. +implementation: > + The probe checks the Archived Status of a project. +outcome: + - If the project is archived, the outcome is OutcomeNegative. + - If the project is not archived, the outcome is OutcomePositive. +remediation: + effort: High + text: + - Non-collaborators, members or owners cannot affect the outcome of this probe. \ No newline at end of file diff --git a/probes/notArchived/impl.go b/probes/notArchived/impl.go new file mode 100644 index 00000000000..057bdcbc46e --- /dev/null +++ b/probes/notArchived/impl.go @@ -0,0 +1,63 @@ +// 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. + +//nolint:stylecheck +package notArchived + +import ( + "embed" + "fmt" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const Probe = "notArchived" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.MaintainedResults + + if r.ArchivedStatus.Status { + return negativeOutcome() + } + return positiveOutcome() +} + +func negativeOutcome() ([]finding.Finding, string, error) { + f, err := finding.NewWith(fs, Probe, + "Repository is archived.", nil, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + return []finding.Finding{*f}, Probe, nil +} + +func positiveOutcome() ([]finding.Finding, string, error) { + f, err := finding.NewWith(fs, Probe, + "Repository is not archived.", nil, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + return []finding.Finding{*f}, Probe, nil +} diff --git a/probes/notArchived/impl_test.go b/probes/notArchived/impl_test.go new file mode 100644 index 00000000000..b65af3bf0ad --- /dev/null +++ b/probes/notArchived/impl_test.go @@ -0,0 +1,91 @@ +// 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. + +//nolint:stylecheck +package notArchived + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "Is archived", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + ArchivedStatus: checker.ArchivedStatus{ + Status: true, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + }, + }, + { + name: "Is not archived", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + ArchivedStatus: checker.ArchivedStatus{ + Status: false, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} diff --git a/probes/notCreatedRecently/def.yml b/probes/notCreatedRecently/def.yml new file mode 100644 index 00000000000..b8a2b20e089 --- /dev/null +++ b/probes/notCreatedRecently/def.yml @@ -0,0 +1,27 @@ +# 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: notCreatedRecently +short: Checks that the project was not created in the last 90 days. +motivation: > + When Scorecard checks the activity of a project in the last 90 days, the project may not have been created before the last 90 days. As such, Scorecard cannot give an accurate score. This probe helps Scorecard assess whether it can give an accurrate score when checking the project activity in the last 90 days. +implementation: > + The implementation checks the creation date is within the last 90 days. +outcome: + - If the project was created within the last 90 days, the outcome is OutcomeNegative (0). + - If the project was created before the last 90 days, the outcome is OutcomePositive (1). The finding will include a "lookBackDays" value which is the time period that the probe looks back in. +remediation: + effort: Low + text: + - The only remediation for this probe is to wait until 90 days have passed after a project has been created. diff --git a/probes/notCreatedRecently/impl.go b/probes/notCreatedRecently/impl.go new file mode 100644 index 00000000000..70919300d7a --- /dev/null +++ b/probes/notCreatedRecently/impl.go @@ -0,0 +1,73 @@ +// 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. + +//nolint:stylecheck +package notCreatedRecently + +import ( + "embed" + "fmt" + "time" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + lookBackDays = 90 +) + +const Probe = "notCreatedRecently" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.MaintainedResults + + recencyThreshold := time.Now().AddDate(0 /*years*/, 0 /*months*/, -1*lookBackDays /*days*/) + + if r.CreatedAt.After(recencyThreshold) { + return negativeOutcome() + } + return positiveOutcome() +} + +func negativeOutcome() ([]finding.Finding, string, error) { + f, err := finding.NewWith(fs, Probe, + "Repository was created in last 90 days.", nil, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + return []finding.Finding{*f}, Probe, nil +} + +func positiveOutcome() ([]finding.Finding, string, error) { + f, err := finding.NewWith(fs, Probe, + "Repository was not created in last 90 days.", nil, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithValues(map[string]int{ + "lookBackDays": 90, + }) + return []finding.Finding{*f}, Probe, nil +} diff --git a/probes/notCreatedRecently/impl_test.go b/probes/notCreatedRecently/impl_test.go new file mode 100644 index 00000000000..1677a54eadd --- /dev/null +++ b/probes/notCreatedRecently/impl_test.go @@ -0,0 +1,88 @@ +// 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. + +//nolint:stylecheck +package notCreatedRecently + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "Was created 10 days ago", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + CreatedAt: time.Now().AddDate(0 /*years*/, 0 /*months*/, -10 /*days*/), + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + }, + }, + { + name: "Was creted 100 days ago", + raw: &checker.RawResults{ + MaintainedResults: checker.MaintainedData{ + CreatedAt: time.Now().AddDate(0 /*years*/, 0 /*months*/, -100 /*days*/), + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} From 82692a802e6e930474f9ffa92d64e94d0ae9af55 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Fri, 17 Nov 2023 10:24:04 -0800 Subject: [PATCH 12/51] :seedling: allow contributors to call scdiff workflow (#3683) also removes the edited trigger. codecov posts 3 times on each PR, which causes this action to trigger 3x. It is skipped though, so not a huge deal. Signed-off-by: Spencer Schrock --- .github/workflows/scdiff.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scdiff.yml b/.github/workflows/scdiff.yml index 3dd02033d8a..7ffc03e6f68 100644 --- a/.github/workflows/scdiff.yml +++ b/.github/workflows/scdiff.yml @@ -1,7 +1,7 @@ name: scdiff PR evaluation on: issue_comment: - types: [created, edited] + types: [created] permissions: read-all @@ -61,7 +61,7 @@ jobs: uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 with: script: | - const allowedAssociations = ["COLLABORATOR", "MEMBER", "OWNER"]; + const allowedAssociations = ["COLLABORATOR", "CONTRIBUTOR", "MEMBER", "OWNER"]; authorAssociation = '${{ github.event.comment.author_association }}' if (!allowedAssociations.includes(authorAssociation)) { core.setFailed("You don't have access to run scdiff"); From 0f0808a0ab2185402e37e6b1863ca85c8cbd4e18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 09:32:28 +0000 Subject: [PATCH 13/51] :seedling: Bump github.com/google/ko from 0.15.0 to 0.15.1 in /tools (#3682) Bumps [github.com/google/ko](https://github.com/google/ko) from 0.15.0 to 0.15.1. - [Release notes](https://github.com/google/ko/releases) - [Changelog](https://github.com/ko-build/ko/blob/main/.goreleaser.yml) - [Commits](https://github.com/google/ko/compare/v0.15.0...v0.15.1) --- updated-dependencies: - dependency-name: github.com/google/ko dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/go.mod | 16 ++++++++-------- tools/go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index 809feb74f0c..24251fe5083 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -6,7 +6,7 @@ require ( github.com/golang/mock v1.6.0 github.com/golangci/golangci-lint v1.55.2 github.com/google/addlicense v1.1.1 - github.com/google/ko v0.15.0 + github.com/google/ko v0.15.1 github.com/goreleaser/goreleaser v1.20.0 github.com/onsi/ginkgo/v2 v2.13.1 google.golang.org/protobuf v1.31.0 @@ -363,18 +363,18 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect gocloud.dev v0.34.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.18.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/term v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/appengine v1.6.8 // indirect @@ -391,7 +391,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.1.0 // indirect honnef.co/go/tools v0.4.6 // indirect - k8s.io/apimachinery v0.28.3 // indirect + k8s.io/apimachinery v0.28.4 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect mvdan.cc/gofumpt v0.5.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index 8161892c094..80e0a08bdce 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -611,8 +611,8 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/ko v0.15.0 h1:p1391YCLBmUXBEapqzswbjk7leqtkceRD7eFr6G7IQQ= -github.com/google/ko v0.15.0/go.mod h1:3IzJ58T/0GWv0IqgpJwwBlCdSDzdHmEdSsWRKXIhMtY= +github.com/google/ko v0.15.1 h1:++5WJTTjSLyObGK6NYdnkHGw4XiUkFD2ldk2mbJ9vd8= +github.com/google/ko v0.15.1/go.mod h1:2hpqDZDqly3yVDZbBCohSnUrmwOXw7MBCqujBBu6rMU= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -1188,8 +1188,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1236,8 +1236,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1287,8 +1287,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1398,8 +1398,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1414,8 +1414,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1498,8 +1498,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1658,8 +1658,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8= honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= -k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= -k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= From a0dfec298c892328ff2d304966a786bb802e04c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 09:58:40 +0000 Subject: [PATCH 14/51] :seedling: Bump golang.org/x/oauth2 from 0.13.0 to 0.14.0 (#3658) Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.13.0 to 0.14.0. - [Commits](https://github.com/golang/oauth2/compare/v0.13.0...v0.14.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 95f39e63153..d0c69bbbe48 100644 --- a/go.mod +++ b/go.mod @@ -106,7 +106,7 @@ require ( github.com/spdx/tools-golang v0.5.3 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect + golang.org/x/term v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/vuln v1.0.1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect @@ -173,12 +173,12 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.13.0 + golang.org/x/net v0.18.0 // indirect + golang.org/x/oauth2 v0.14.0 golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 27b45dcb66f..b4bb30ffb8e 100644 --- a/go.sum +++ b/go.sum @@ -836,8 +836,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -921,15 +921,15 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1002,8 +1002,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1012,8 +1012,8 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 0276a7cd7284e077f22b50208345201485029fbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 10:13:38 +0000 Subject: [PATCH 15/51] :seedling: Bump github.com/onsi/ginkgo/v2 from 2.13.0 to 2.13.1 (#3669) Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.0...v2.13.1) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d0c69bbbe48..fa507233557 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/google/go-github/v53 v53.2.0 github.com/google/osv-scanner v1.4.3 github.com/mcuadros/go-jsonschema-generator v0.0.0-20200330054847-ba7a369d4303 - github.com/onsi/ginkgo/v2 v2.13.0 + github.com/onsi/ginkgo/v2 v2.13.1 github.com/otiai10/copy v1.14.0 sigs.k8s.io/release-utils v0.6.0 ) diff --git a/go.sum b/go.sum index b4bb30ffb8e..aca32485a36 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= +github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= From 76878e5b4da07aa6d3c9ca7cd426346007673383 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 12:16:39 -0500 Subject: [PATCH 16/51] :seedling: Bump the github-actions group with 2 updates (#3686) Bumps the github-actions group with 2 updates: [step-security/harden-runner](https://github.com/step-security/harden-runner) and [actions/github-script](https://github.com/actions/github-script). Updates `step-security/harden-runner` from 2.6.0 to 2.6.1 - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/1b05615854632b887b69ae1be8cbefe72d3ae423...eb238b55efaa70779f274895e782ed17c84f2895) Updates `actions/github-script` from 6.4.1 to 7.0.1 - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/d7906e4ad0b1822421a7e6a35d5ca353c962f410...60a0d83039c74a4aee543508d2ffcb1c3799cdea) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/gitlab.yml | 2 +- .github/workflows/goreleaser.yaml | 2 +- .github/workflows/integration.yml | 4 ++-- .github/workflows/lint.yml | 2 +- .github/workflows/main.yml | 18 +++++++++--------- .github/workflows/publishimage.yml | 2 +- .github/workflows/scdiff.yml | 4 ++-- .github/workflows/stale.yml | 2 +- .github/workflows/verify.yml | 2 +- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b31a4696541..a58103355c9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -52,7 +52,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3874978c9f6..7fea70efaa7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -70,7 +70,7 @@ jobs: steps: - name: Harden Runner if: (needs.docs_only_check.outputs.docs_only != 'true') - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Clone the code diff --git a/.github/workflows/gitlab.yml b/.github/workflows/gitlab.yml index ce248f1e7c7..4084a0d4ecc 100644 --- a/.github/workflows/gitlab.yml +++ b/.github/workflows/gitlab.yml @@ -33,7 +33,7 @@ jobs: environment: gitlab steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Clone the code diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml index 782191e9ab7..41ad2ea1665 100644 --- a/.github/workflows/goreleaser.yaml +++ b/.github/workflows/goreleaser.yaml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 710813f8684..5be19ddddae 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -44,7 +44,7 @@ jobs: needs: [approve] steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Clone the code diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4e138a680c6..cd26d590dea 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,7 +19,7 @@ jobs: name: check-linter runs-on: ubuntu-latest steps: - - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + - uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b3d91a8ab37..d24685c62f6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Clone the code @@ -95,7 +95,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -143,7 +143,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Clone the code @@ -172,7 +172,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -221,7 +221,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Cache builds @@ -260,7 +260,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -303,7 +303,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Install Protoc @@ -349,7 +349,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -384,7 +384,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/publishimage.yml b/.github/workflows/publishimage.yml index 876b97b5ee8..4d0fb9ef6bc 100644 --- a/.github/workflows/publishimage.yml +++ b/.github/workflows/publishimage.yml @@ -35,7 +35,7 @@ jobs: COSIGN_EXPERIMENTAL: "true" steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/scdiff.yml b/.github/workflows/scdiff.yml index 7ffc03e6f68..e457fc890e6 100644 --- a/.github/workflows/scdiff.yml +++ b/.github/workflows/scdiff.yml @@ -16,7 +16,7 @@ jobs: pull-requests: write # to create the PR comment steps: - name: share link to workflow run - uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | github.rest.issues.createComment({ @@ -58,7 +58,7 @@ jobs: echo "body=$BODY" >> $GITHUB_OUTPUT - name: configure scdiff id: config - uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const allowedAssociations = ["COLLABORATOR", "CONTRIBUTOR", "MEMBER", "OWNER"]; diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 8dbc78bf632..974bfed6c9f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 2dba7a8e5af..78bc7d0b1e1 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v1 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs From 1a17bb812fb2ac23e9d09e86e122f8b67563aed7 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Mon, 20 Nov 2023 13:12:09 -0800 Subject: [PATCH 17/51] :bug: add retry loop to graphQL commit queries which timeout on large github repos (#3680) * try to always paginate in the event of timeouts, make our pagination smaller Signed-off-by: Spencer Schrock * add retry test Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- clients/githubrepo/graphql.go | 48 +++++++++++++------------- clients/githubrepo/graphql_test.go | 54 ++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 clients/githubrepo/graphql_test.go diff --git a/clients/githubrepo/graphql.go b/clients/githubrepo/graphql.go index 42b9adb3a65..e3fa19128b2 100644 --- a/clients/githubrepo/graphql.go +++ b/clients/githubrepo/graphql.go @@ -34,6 +34,10 @@ const ( issueCommentsToAnalyze = 30 reviewsToAnalyze = 30 labelsToAnalyze = 30 + + // https://docs.github.com/en/graphql/overview/rate-limits-and-node-limits-for-the-graphql-api#node-limit + defaultPageLimit = 100 + retryLimit = 3 ) //nolint:govet @@ -155,28 +159,35 @@ func (handler *graphqlHandler) init(ctx context.Context, repourl *repoURL, commi } func populateCommits(handler *graphqlHandler, vars map[string]interface{}) ([]clients.Commit, error) { - var allCommits []clients.Commit - var commitsLeft githubv4.Int + var commits []clients.Commit commitsLeft, ok := vars["commitsToAnalyze"].(githubv4.Int) if !ok { - return nil, nil + return nil, sce.WithMessage(sce.ErrScorecardInternal, "unexpected type") } - for vars["commitsToAnalyze"] = githubv4.Int(100); commitsLeft > 0; commitsLeft = commitsLeft - 100 { - if commitsLeft < 100 { - vars["commitsToAnalyze"] = commitsLeft - } - err := handler.client.Query(handler.ctx, handler.data, vars) - if err != nil { - return nil, fmt.Errorf("failed to populate commits: %w", err) + commitsRequested := min(defaultPageLimit, commitsLeft) + var retries int + for commitsLeft > 0 { + vars["commitsToAnalyze"] = commitsRequested + if err := handler.client.Query(handler.ctx, handler.data, vars); err != nil { + // 502 usually indicate timeouts, where we're requesting too much data + // so make our requests smaller and try again + if retries < retryLimit && strings.Contains(err.Error(), "502 Bad Gateway") { + retries++ + commitsRequested /= 2 + continue + } + return nil, sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("githubv4.Query: %v", err)) } vars["historyCursor"] = handler.data.Repository.Object.Commit.History.PageInfo.EndCursor tmp, err := commitsFrom(handler.data, handler.repourl.owner, handler.repourl.repo) if err != nil { return nil, fmt.Errorf("failed to populate commits: %w", err) } - allCommits = append(allCommits, tmp...) + commits = append(commits, tmp...) + commitsLeft -= commitsRequested + commitsRequested = min(commitsRequested, commitsLeft) } - return allCommits, nil + return commits, nil } func (handler *graphqlHandler) setup() error { @@ -194,18 +205,7 @@ func (handler *graphqlHandler) setup() error { "commitExpression": githubv4.String(commitExpression), "historyCursor": (*githubv4.String)(nil), } - // if NumberOfCommits set to < 99 we are required by the graphql to page by 100 commits. - if handler.commitDepth > 99 { - handler.commits, handler.errSetup = populateCommits(handler, vars) - handler.issues = issuesFrom(handler.data) - handler.archived = bool(handler.data.Repository.IsArchived) - return - } - if err := handler.client.Query(handler.ctx, handler.data, vars); err != nil { - handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("githubv4.Query: %v", err)) - return - } - handler.commits, handler.errSetup = commitsFrom(handler.data, handler.repourl.owner, handler.repourl.repo) + handler.commits, handler.errSetup = populateCommits(handler, vars) handler.issues = issuesFrom(handler.data) handler.archived = bool(handler.data.Repository.IsArchived) }) diff --git a/clients/githubrepo/graphql_test.go b/clients/githubrepo/graphql_test.go new file mode 100644 index 00000000000..0edb5243a6c --- /dev/null +++ b/clients/githubrepo/graphql_test.go @@ -0,0 +1,54 @@ +// 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 githubrepo + +import ( + "context" + "net/http" + "testing" + + "github.com/shurcooL/githubv4" +) + +type badGatewayRoundTripper struct { + requestCounter *int +} + +func (b badGatewayRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { + *b.requestCounter += 1 + return &http.Response{ + StatusCode: http.StatusBadGateway, + Status: "502 Bad Gateway", + }, nil +} + +func Test_getCommits_retry(t *testing.T) { + var nRequests int + rt := badGatewayRoundTripper{requestCounter: &nRequests} + handler := graphqlHandler{ + client: githubv4.NewClient(&http.Client{ + Transport: rt, + }), + } + handler.init(context.Background(), &repoURL{}, 1) + _, err := handler.getCommits() + if err == nil { + t.Error("expected error") + } + want := retryLimit + 1 // 1 represents the initial request + if *rt.requestCounter != want { + t.Errorf("wanted %d retries, got %d", want, *rt.requestCounter) + } +} From f8198b06215375679bcdc72614179529a19202ff Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Mon, 27 Nov 2023 18:10:09 +0000 Subject: [PATCH 18/51] :seedling: refactor pinned dependencies (#3667) * :seedling: refactor pinned dependencies Signed-off-by: AdamKorcz * remove remediation from test Signed-off-by: AdamKorcz --------- Signed-off-by: AdamKorcz --- checks/evaluation/pinned_dependencies.go | 244 ++++++++++++++---- checks/evaluation/pinned_dependencies_test.go | 114 ++++---- 2 files changed, 234 insertions(+), 124 deletions(-) diff --git a/checks/evaluation/pinned_dependencies.go b/checks/evaluation/pinned_dependencies.go index b5672bc10b8..762a4359073 100644 --- a/checks/evaluation/pinned_dependencies.go +++ b/checks/evaluation/pinned_dependencies.go @@ -21,6 +21,8 @@ import ( "github.com/ossf/scorecard/v4/checks/fileparser" 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/rule" ) type pinnedResult struct { @@ -49,6 +51,141 @@ const ( normalWeight int = gitHubOwnedActionWeight + thirdPartyActionWeight ) +var ( + dependencyTypes = map[checker.DependencyUseType]int{ + checker.DependencyUseTypeGHAction: 0, + checker.DependencyUseTypeDockerfileContainerImage: 1, + checker.DependencyUseTypeDownloadThenRun: 2, + checker.DependencyUseTypeGoCommand: 3, + checker.DependencyUseTypeChocoCommand: 4, + checker.DependencyUseTypeNpmCommand: 5, + checker.DependencyUseTypePipCommand: 6, + checker.DependencyUseTypeNugetCommand: 7, + } + intToDepType = map[int]checker.DependencyUseType{ + 0: checker.DependencyUseTypeGHAction, + 1: checker.DependencyUseTypeDockerfileContainerImage, + 2: checker.DependencyUseTypeDownloadThenRun, + 3: checker.DependencyUseTypeGoCommand, + 4: checker.DependencyUseTypeChocoCommand, + 5: checker.DependencyUseTypeNpmCommand, + 6: checker.DependencyUseTypePipCommand, + 7: checker.DependencyUseTypeNugetCommand, + } +) + +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, + Text: rem.Text, + Markdown: rem.Markdown, + Effort: rule.RemediationEffort(rem.Effort), + } +} + +func dependenciesToFindings(deps []checker.Dependency) ([]finding.Finding, error) { + findings := make([]finding.Finding, 0) + for i := range deps { + rr := deps[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.WithValues(map[string]int{ + "dependencyType": dependencyTypes[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.WithValues(map[string]int{ + "dependencyType": dependencyTypes[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, @@ -72,53 +209,47 @@ func PinningDependencies(name string, c *checker.CheckRequest, }) } - 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 checker.CreateRuntimeErrorResult(name, e) + findings, err := dependenciesToFindings(r.Dependencies) + if err != nil { + return checker.CreateRuntimeErrorResult(name, err) + } + + for i := range findings { + f := findings[i] + if f.Outcome == finding.OutcomeNotApplicable { + if f.Location != nil { + dl.Debug(&checker.LogMessage{ + Path: f.Location.Path, + Type: f.Location.Type, + Offset: *f.Location.LineStart, + EndOffset: *f.Location.LineEnd, + Text: f.Message, + Snippet: *f.Location.Snippet, + }) + } else { + dl.Debug(&checker.LogMessage{ + Text: f.Message, + }) } - dl.Debug(&checker.LogMessage{ - Text: *rr.Msg, - }) continue + } else if f.Outcome == finding.OutcomeNegative { + lm := &checker.LogMessage{ + Path: f.Location.Path, + Type: f.Location.Type, + Offset: *f.Location.LineStart, + EndOffset: *f.Location.LineEnd, + Text: f.Message, + Snippet: *f.Location.Snippet, + } + + if f.Remediation != nil { + lm.Remediation = probeRemToRuleRem(f.Remediation) + } + dl.Warn(lm) } - if rr.Msg != nil { - dl.Debug(&checker.LogMessage{ - Path: rr.Location.Path, - Type: rr.Location.Type, - Offset: rr.Location.Offset, - EndOffset: rr.Location.EndOffset, - Text: *rr.Msg, - Snippet: rr.Location.Snippet, - }) - continue - } - if rr.Pinned == nil { - dl.Debug(&checker.LogMessage{ - Path: rr.Location.Path, - Type: rr.Location.Type, - Offset: rr.Location.Offset, - EndOffset: rr.Location.EndOffset, - Text: fmt.Sprintf("%s has empty Pinned field", rr.Type), - Snippet: rr.Location.Snippet, - }) - continue - } - if !*rr.Pinned { - dl.Warn(&checker.LogMessage{ - Path: rr.Location.Path, - Type: rr.Location.Type, - Offset: rr.Location.Offset, - EndOffset: rr.Location.EndOffset, - Text: generateTextUnpinned(&rr), - Snippet: rr.Location.Snippet, - Remediation: rr.Remediation, - }) - } - // Update the pinning status. - updatePinningResults(&rr, &wp, pr) + updatePinningResults(intToDepType[f.Values["dependencyType"]], + f.Outcome, f.Location.Snippet, + &wp, pr) } // Generate scores and Info results. @@ -155,21 +286,22 @@ func PinningDependencies(name string, c *checker.CheckRequest, "dependency not pinned by hash detected", score, checker.MaxResultScore) } -func updatePinningResults(rr *checker.Dependency, +func updatePinningResults(dependencyType checker.DependencyUseType, + outcome finding.Outcome, snippet *string, wp *worklowPinningResult, pr map[checker.DependencyUseType]pinnedResult, ) { - if rr.Type == checker.DependencyUseTypeGHAction { + if dependencyType == checker.DependencyUseTypeGHAction { // Note: `Snippet` contains `action/name@xxx`, so we cna use it to infer // if it's a GitHub-owned action or not. - gitHubOwned := fileparser.IsGitHubOwnedAction(rr.Location.Snippet) - addWorkflowPinnedResult(rr, wp, gitHubOwned) + gitHubOwned := fileparser.IsGitHubOwnedAction(*snippet) + addWorkflowPinnedResult(outcome, wp, gitHubOwned) return } // Update other result types. - p := pr[rr.Type] - addPinnedResult(rr, &p) - pr[rr.Type] = p + p := pr[dependencyType] + addPinnedResult(outcome, &p) + pr[dependencyType] = p } func generateTextUnpinned(rr *checker.Dependency) string { @@ -194,18 +326,18 @@ func generateOwnerToDisplay(gitHubOwned bool) string { return fmt.Sprintf("third-party %s", checker.DependencyUseTypeGHAction) } -func addPinnedResult(rr *checker.Dependency, r *pinnedResult) { - if *rr.Pinned { +func addPinnedResult(outcome finding.Outcome, r *pinnedResult) { + if outcome == finding.OutcomePositive { r.pinned += 1 } r.total += 1 } -func addWorkflowPinnedResult(rr *checker.Dependency, w *worklowPinningResult, isGitHub bool) { +func addWorkflowPinnedResult(outcome finding.Outcome, w *worklowPinningResult, isGitHub bool) { if isGitHub { - addPinnedResult(rr, &w.gitHubOwned) + addPinnedResult(outcome, &w.gitHubOwned) } else { - addPinnedResult(rr, &w.thirdParties) + addPinnedResult(outcome, &w.thirdParties) } } diff --git a/checks/evaluation/pinned_dependencies_test.go b/checks/evaluation/pinned_dependencies_test.go index b4ee3e13372..c90c07e7246 100644 --- a/checks/evaluation/pinned_dependencies_test.go +++ b/checks/evaluation/pinned_dependencies_test.go @@ -848,6 +848,10 @@ func Test_PinningDependencies(t *testing.T) { } } +func stringAsPointer(s string) *string { + return &s +} + func Test_generateOwnerToDisplay(t *testing.T) { t.Parallel() tests := []struct { //nolint:govet @@ -880,9 +884,9 @@ func Test_generateOwnerToDisplay(t *testing.T) { func Test_addWorkflowPinnedResult(t *testing.T) { t.Parallel() type args struct { - dependency *checker.Dependency - w *worklowPinningResult - isGitHub bool + w *worklowPinningResult + outcome finding.Outcome + isGitHub bool } tests := []struct { name string @@ -892,9 +896,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { { name: "add pinned GitHub-owned action dependency", args: args{ - dependency: &checker.Dependency{ - Pinned: asBoolPointer(true), - }, + outcome: finding.OutcomePositive, w: &worklowPinningResult{}, isGitHub: true, }, @@ -912,9 +914,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { { name: "add unpinned GitHub-owned action dependency", args: args{ - dependency: &checker.Dependency{ - Pinned: asBoolPointer(false), - }, + outcome: finding.OutcomeNegative, w: &worklowPinningResult{}, isGitHub: true, }, @@ -932,9 +932,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { { name: "add pinned Third-Party action dependency", args: args{ - dependency: &checker.Dependency{ - Pinned: asBoolPointer(true), - }, + outcome: finding.OutcomePositive, w: &worklowPinningResult{}, isGitHub: false, }, @@ -952,9 +950,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { { name: "add unpinned Third-Party action dependency", args: args{ - dependency: &checker.Dependency{ - Pinned: asBoolPointer(false), - }, + outcome: finding.OutcomeNegative, w: &worklowPinningResult{}, isGitHub: false, }, @@ -974,7 +970,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - addWorkflowPinnedResult(tt.args.dependency, tt.args.w, tt.args.isGitHub) + addWorkflowPinnedResult(tt.args.outcome, tt.args.w, tt.args.isGitHub) if tt.want.thirdParties != tt.args.w.thirdParties { t.Errorf("addWorkflowPinnedResult Third-party GitHub actions mismatch (-want +got):"+ "\nThird-party pinned: %s\nThird-party total: %s", @@ -1032,9 +1028,11 @@ func TestGenerateText(t *testing.T) { func TestUpdatePinningResults(t *testing.T) { t.Parallel() type args struct { - dependency *checker.Dependency - w *worklowPinningResult - pr map[checker.DependencyUseType]pinnedResult + snippet *string + w *worklowPinningResult + pr map[checker.DependencyUseType]pinnedResult + dependencyType checker.DependencyUseType + outcome finding.Outcome } type want struct { w *worklowPinningResult @@ -1048,15 +1046,11 @@ func TestUpdatePinningResults(t *testing.T) { { name: "add pinned GitHub-owned action", args: args{ - dependency: &checker.Dependency{ - Type: checker.DependencyUseTypeGHAction, - Location: &checker.File{ - Snippet: "actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675", - }, - Pinned: asBoolPointer(true), - }, - w: &worklowPinningResult{}, - pr: make(map[checker.DependencyUseType]pinnedResult), + dependencyType: checker.DependencyUseTypeGHAction, + outcome: finding.OutcomePositive, + snippet: stringAsPointer("actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675"), + w: &worklowPinningResult{}, + pr: make(map[checker.DependencyUseType]pinnedResult), }, want: want{ w: &worklowPinningResult{ @@ -1075,15 +1069,11 @@ func TestUpdatePinningResults(t *testing.T) { { name: "add unpinned GitHub-owned action", args: args{ - dependency: &checker.Dependency{ - Type: checker.DependencyUseTypeGHAction, - Location: &checker.File{ - Snippet: "actions/checkout@v2", - }, - Pinned: asBoolPointer(false), - }, - w: &worklowPinningResult{}, - pr: make(map[checker.DependencyUseType]pinnedResult), + dependencyType: checker.DependencyUseTypeGHAction, + outcome: finding.OutcomeNegative, + snippet: stringAsPointer("actions/checkout@v2"), + w: &worklowPinningResult{}, + pr: make(map[checker.DependencyUseType]pinnedResult), }, want: want{ w: &worklowPinningResult{ @@ -1102,15 +1092,11 @@ func TestUpdatePinningResults(t *testing.T) { { name: "add pinned Third-party action", args: args{ - dependency: &checker.Dependency{ - Type: checker.DependencyUseTypeGHAction, - Location: &checker.File{ - Snippet: "other/checkout@ffa6706ff2127a749973072756f83c532e43ed02", - }, - Pinned: asBoolPointer(true), - }, - w: &worklowPinningResult{}, - pr: make(map[checker.DependencyUseType]pinnedResult), + dependencyType: checker.DependencyUseTypeGHAction, + outcome: finding.OutcomePositive, + w: &worklowPinningResult{}, + snippet: stringAsPointer("other/checkout@ffa6706ff2127a749973072756f83c532e43ed02"), + pr: make(map[checker.DependencyUseType]pinnedResult), }, want: want{ w: &worklowPinningResult{ @@ -1129,15 +1115,11 @@ func TestUpdatePinningResults(t *testing.T) { { name: "add unpinned Third-party action", args: args{ - dependency: &checker.Dependency{ - Type: checker.DependencyUseTypeGHAction, - Location: &checker.File{ - Snippet: "other/checkout@v2", - }, - Pinned: asBoolPointer(false), - }, - w: &worklowPinningResult{}, - pr: make(map[checker.DependencyUseType]pinnedResult), + dependencyType: checker.DependencyUseTypeGHAction, + snippet: stringAsPointer("other/checkout@v2"), + outcome: finding.OutcomeNegative, + w: &worklowPinningResult{}, + pr: make(map[checker.DependencyUseType]pinnedResult), }, want: want{ w: &worklowPinningResult{ @@ -1156,12 +1138,10 @@ func TestUpdatePinningResults(t *testing.T) { { name: "add pinned pip install", args: args{ - dependency: &checker.Dependency{ - Type: checker.DependencyUseTypePipCommand, - Pinned: asBoolPointer(true), - }, - w: &worklowPinningResult{}, - pr: make(map[checker.DependencyUseType]pinnedResult), + dependencyType: checker.DependencyUseTypePipCommand, + outcome: finding.OutcomePositive, + w: &worklowPinningResult{}, + pr: make(map[checker.DependencyUseType]pinnedResult), }, want: want{ w: &worklowPinningResult{}, @@ -1176,12 +1156,10 @@ func TestUpdatePinningResults(t *testing.T) { { name: "add unpinned pip install", args: args{ - dependency: &checker.Dependency{ - Type: checker.DependencyUseTypePipCommand, - Pinned: asBoolPointer(false), - }, - w: &worklowPinningResult{}, - pr: make(map[checker.DependencyUseType]pinnedResult), + dependencyType: checker.DependencyUseTypePipCommand, + outcome: finding.OutcomeNegative, + w: &worklowPinningResult{}, + pr: make(map[checker.DependencyUseType]pinnedResult), }, want: want{ w: &worklowPinningResult{}, @@ -1198,7 +1176,7 @@ func TestUpdatePinningResults(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() - updatePinningResults(tc.args.dependency, tc.args.w, tc.args.pr) + updatePinningResults(tc.args.dependencyType, tc.args.outcome, tc.args.snippet, tc.args.w, tc.args.pr) if tc.want.w.thirdParties != tc.args.w.thirdParties { t.Errorf("updatePinningResults Third-party GitHub actions mismatch (-want +got):"+ "\nThird-party pinned: %s\nThird-party total: %s", From 84bd607ae8c1b3d53c64172adcc0228e8f6ae298 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Mon, 27 Nov 2023 15:10:51 -0800 Subject: [PATCH 19/51] :seedling: fix script injection (#3695) Thanks to @AdnaneKhan for the report. * start with reporter patch * use env variable for bash step too Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- .github/workflows/scdiff.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/scdiff.yml b/.github/workflows/scdiff.yml index e457fc890e6..ba809e28a2e 100644 --- a/.github/workflows/scdiff.yml +++ b/.github/workflows/scdiff.yml @@ -49,15 +49,10 @@ jobs: https://gitlab.com/baserow/baserow https://gitlab.com/cryptsetup/cryptsetup EOF - # use shell syntax to escape, since the checks arg goes to CLI when calling scdiff - - name: escape comment body - id: comment - env: - BODY: ${{ github.event.comment.body }} - run: | - echo "body=$BODY" >> $GITHUB_OUTPUT - name: configure scdiff id: config + env: + COMMENT_BODY: ${{ github.event.comment.body }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | @@ -76,13 +71,13 @@ jobs: core.setOutput('head', response.data.head.sha) checks = '""' - const commentBody = '${{ steps.comment.outputs.body }}' + const commentBody = process.env.COMMENT_BODY const regex = /\/scdiff generate ([^ ]+)/; const found = commentBody.match(regex); if (found && found.length == 2) { checks = found[1] } - core.setOutput('checks', checks) + core.exportVariable('SCORECARD_CHECKS', checks) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ steps.config.outputs.base }} @@ -98,7 +93,7 @@ jobs: run: | go run cmd/internal/scdiff/main.go generate \ --repos $HOME/repos.txt \ - --checks ${{ steps.config.outputs.checks }} > $HOME/before.json + --checks $SCORECARD_CHECKS > $HOME/before.json - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ steps.config.outputs.head }} @@ -109,7 +104,7 @@ jobs: run: | go run cmd/internal/scdiff/main.go generate \ --repos $HOME/repos.txt \ - --checks ${{ steps.config.outputs.checks }} > $HOME/after.json + --checks $SCORECARD_CHECKS > $HOME/after.json - name: compare results run: | go run cmd/internal/scdiff/main.go compare $HOME/before.json $HOME/after.json From 04ea8bee4898d042ca8d7cc947a42d401d435340 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:26:49 -0500 Subject: [PATCH 20/51] :seedling: Bump github.com/go-git/go-git/v5 from 5.10.0 to 5.10.1 (#3698) Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.10.0 to 5.10.1. - [Release notes](https://github.com/go-git/go-git/releases) - [Commits](https://github.com/go-git/go-git/compare/v5.10.0...v5.10.1) --- updated-dependencies: - dependency-name: github.com/go-git/go-git/v5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 +-- go.sum | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index fa507233557..456eec206c4 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.14 github.com/bombsimon/logrusr/v2 v2.0.1 github.com/bradleyfalzon/ghinstallation/v2 v2.8.0 - github.com/go-git/go-git/v5 v5.10.0 + github.com/go-git/go-git/v5 v5.10.1 github.com/go-logr/logr v1.3.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 @@ -130,7 +130,6 @@ require ( cloud.google.com/go/storage v1.31.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect - github.com/acomagu/bufpipe v1.0.4 // indirect github.com/aws/aws-sdk-go v1.44.314 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect diff --git a/go.sum b/go.sum index aca32485a36..3acf5f1c25e 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,6 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= -github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= @@ -287,8 +285,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+ github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.10.0 h1:F0x3xXrAWmhwtzoCokU4IMPcBdncG+HAAqi9FcOOjbQ= -github.com/go-git/go-git/v5 v5.10.0/go.mod h1:1FOZ/pQnqw24ghP2n7cunVl0ON55BsjPYvhWHvZGhoo= +github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk= +github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -564,8 +562,6 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= From 68573209d6d7df7e44e67cd6ffb68abfff0e1b68 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:30:06 +0000 Subject: [PATCH 21/51] :seedling: make maintained values keys constants (#3700) Signed-off-by: Adam Korczynski Co-authored-by: Raghav Kaul <8695110+raghavkaul@users.noreply.github.com> --- checks/evaluation/maintained.go | 4 ++-- probes/hasRecentCommits/impl.go | 8 +++++--- probes/issueActivityByProjectMember/impl.go | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/checks/evaluation/maintained.go b/checks/evaluation/maintained.go index bf4daeee897..3be51d577cb 100644 --- a/checks/evaluation/maintained.go +++ b/checks/evaluation/maintained.go @@ -67,9 +67,9 @@ func Maintained(name string, if f.Outcome == finding.OutcomePositive { switch f.Probe { case issueActivityByProjectMember.Probe: - numberOfIssuesUpdatedWithinThreshold = f.Values["numberOfIssuesUpdatedWithinThreshold"] + numberOfIssuesUpdatedWithinThreshold = f.Values[issueActivityByProjectMember.NoOfIssuesValue] case hasRecentCommits.Probe: - commitsWithinThreshold = f.Values["commitsWithinThreshold"] + commitsWithinThreshold = f.Values[hasRecentCommits.CommitsValue] } } } diff --git a/probes/hasRecentCommits/impl.go b/probes/hasRecentCommits/impl.go index fbd3abbd28e..8b4fb866003 100644 --- a/probes/hasRecentCommits/impl.go +++ b/probes/hasRecentCommits/impl.go @@ -29,7 +29,9 @@ import ( var fs embed.FS const ( - lookBackDays = 90 + lookBackDays = 90 + CommitsValue = "commitsWithinThreshold" + LookBackValue = "lookBackDays" ) const Probe = "hasRecentCommits" @@ -60,8 +62,8 @@ func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { return nil, Probe, fmt.Errorf("create finding: %w", err) } f = f.WithValues(map[string]int{ - "commitsWithinThreshold": commitsWithinThreshold, - "lookBackDays": 90, + CommitsValue: commitsWithinThreshold, + LookBackValue: lookBackDays, }) findings = append(findings, *f) } else { diff --git a/probes/issueActivityByProjectMember/impl.go b/probes/issueActivityByProjectMember/impl.go index 493c075ac74..04d000cd4f2 100644 --- a/probes/issueActivityByProjectMember/impl.go +++ b/probes/issueActivityByProjectMember/impl.go @@ -30,7 +30,8 @@ import ( var fs embed.FS const ( - lookBackDays = 90 + lookBackDays = 90 + NoOfIssuesValue = "numberOfIssuesUpdatedWithinThreshold" ) const Probe = "issueActivityByProjectMember" @@ -60,7 +61,7 @@ func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { return nil, Probe, fmt.Errorf("create finding: %w", err) } f = f.WithValues(map[string]int{ - "numberOfIssuesUpdatedWithinThreshold": numberOfIssuesUpdatedWithinThreshold, + NoOfIssuesValue: numberOfIssuesUpdatedWithinThreshold, }) findings = append(findings, *f) } else { From 9b5d762a7d4f2fdb4841344524c0c88657290334 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:02:26 +0000 Subject: [PATCH 22/51] :seedling: convert CII Best Practices check to probes (#3520) * :seedling: convert CII Best Practices check to probes Signed-off-by: AdamKorcz * change 'NOT' to 'not' Signed-off-by: AdamKorcz * Change wording in probes Signed-off-by: AdamKorcz * add links to text Signed-off-by: AdamKorcz * fix typo Signed-off-by: AdamKorcz * Edit text in def.yml Signed-off-by: AdamKorcz * remove hasBadgeNotFound probe Signed-off-by: AdamKorcz * remove 'that' from text Signed-off-by: AdamKorcz * use CreateMinScoreResult instead of CreateResultWithScore Signed-off-by: AdamKorcz * use MaxResultScore instead of maxScore Signed-off-by: AdamKorcz * return CreateRuntimeErrorResult sooner rather than later Signed-off-by: AdamKorcz * Combine probes into one Signed-off-by: Adam Korczynski * remove minScore variable Signed-off-by: Adam Korczynski * remove 'hasInProgressBadge' probe Signed-off-by: Adam Korczynski * make badge levels global variables Signed-off-by: Adam Korczynski * return -1 for unsupported badge Signed-off-by: Adam Korczynski * change text for unknown and unsupported badges Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- checks/cii_best_practices.go | 16 +- checks/evaluation/cii_best_practices.go | 75 +++++--- checks/evaluation/cii_best_practices_test.go | 189 +++++++++++++------ probes/entries.go | 4 + probes/hasOpenSSFBadge/def.yml | 29 +++ probes/hasOpenSSFBadge/impl.go | 80 ++++++++ probes/hasOpenSSFBadge/impl_test.go | 121 ++++++++++++ 7 files changed, 421 insertions(+), 93 deletions(-) create mode 100644 probes/hasOpenSSFBadge/def.yml create mode 100644 probes/hasOpenSSFBadge/impl.go create mode 100644 probes/hasOpenSSFBadge/impl_test.go diff --git a/checks/cii_best_practices.go b/checks/cii_best_practices.go index fd7f5679ff0..4f39c9c78e3 100644 --- a/checks/cii_best_practices.go +++ b/checks/cii_best_practices.go @@ -19,6 +19,8 @@ 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" + "github.com/ossf/scorecard/v4/probes/zrunner" ) // CheckCIIBestPractices is the registered name for CIIBestPractices. @@ -40,11 +42,17 @@ func CIIBestPractices(c *checker.CheckRequest) checker.CheckResult { return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e) } - // Return raw results. - if c.RawResults != nil { - c.RawResults.CIIBestPracticesResults = rawData + // Set the raw results. + pRawResults := getRawResults(c) + pRawResults.CIIBestPracticesResults = rawData + + // Evaluate the probes. + findings, err := zrunner.Run(pRawResults, probes.CIIBestPractices) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e) } // Return the score evaluation. - return evaluation.CIIBestPractices(CheckCIIBestPractices, c.Dlogger, &rawData) + return evaluation.CIIBestPractices(CheckCIIBestPractices, findings, c.Dlogger) } diff --git a/checks/evaluation/cii_best_practices.go b/checks/evaluation/cii_best_practices.go index fa940b4c0ba..0dd8511cf38 100644 --- a/checks/evaluation/cii_best_practices.go +++ b/checks/evaluation/cii_best_practices.go @@ -15,14 +15,12 @@ package evaluation import ( - "fmt" - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" sce "github.com/ossf/scorecard/v4/errors" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/hasOpenSSFBadge" ) -// Note: exported for unit tests. const ( silverScore = 7 // Note: if this value is changed, please update the action's threshold score @@ -32,31 +30,54 @@ const ( ) // CIIBestPractices applies the score policy for the CIIBestPractices check. -func CIIBestPractices(name string, _ checker.DetailLogger, r *checker.CIIBestPracticesData) checker.CheckResult { - if r == nil { - e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") +func CIIBestPractices(name string, + findings []finding.Finding, dl checker.DetailLogger, +) checker.CheckResult { + expectedProbes := []string{ + hasOpenSSFBadge.Probe, + } + + if !finding.UniqueProbesEqual(findings, expectedProbes) { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results") return checker.CreateRuntimeErrorResult(name, e) } - var results checker.CheckResult - switch r.Badge { - case clients.NotFound: - results = checker.CreateMinScoreResult(name, "no effort to earn an OpenSSF best practices badge detected") - case clients.InProgress: - msg := fmt.Sprintf("badge detected: %v", r.Badge) - results = checker.CreateResultWithScore(name, msg, inProgressScore) - case clients.Passing: - msg := fmt.Sprintf("badge detected: %v", r.Badge) - results = checker.CreateResultWithScore(name, msg, passingScore) - case clients.Silver: - msg := fmt.Sprintf("badge detected: %v", r.Badge) - results = checker.CreateResultWithScore(name, msg, silverScore) - case clients.Gold: - msg := fmt.Sprintf("badge detected: %v", r.Badge) - results = checker.CreateMaxScoreResult(name, msg) - case clients.Unknown: - e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", r.Badge)) - results = checker.CreateRuntimeErrorResult(name, e) + var score int + var text string + + if len(findings) != 1 { + errText := "invalid probe results: multiple findings detected" + e := sce.WithMessage(sce.ErrScorecardInternal, errText) + return checker.CreateRuntimeErrorResult(name, e) } - return results + + f := &findings[0] + if f.Outcome == finding.OutcomeNegative { + text = "no effort to earn an OpenSSF best practices badge detected" + return checker.CreateMinScoreResult(name, text) + } + //nolint:nestif + if _, hasKey := f.Values[hasOpenSSFBadge.GoldLevel]; hasKey { + score = checker.MaxResultScore + text = "badge detected: Gold" + } else if _, hasKey := f.Values[hasOpenSSFBadge.SilverLevel]; hasKey { + score = silverScore + text = "badge detected: Silver" + } else if _, hasKey := f.Values[hasOpenSSFBadge.PassingLevel]; hasKey { + score = passingScore + text = "badge detected: Passing" + } else if _, hasKey := f.Values[hasOpenSSFBadge.InProgressLevel]; hasKey { + score = inProgressScore + text = "badge detected: InProgress" + } else if _, hasKey := f.Values[hasOpenSSFBadge.UnknownLevel]; hasKey { + text = "unknown badge detected" + e := sce.WithMessage(sce.ErrScorecardInternal, text) + return checker.CreateRuntimeErrorResult(name, e) + } else { + text = "unsupported badge detected" + e := sce.WithMessage(sce.ErrScorecardInternal, text) + return checker.CreateRuntimeErrorResult(name, e) + } + + return checker.CreateResultWithScore(name, text, score) } diff --git a/checks/evaluation/cii_best_practices_test.go b/checks/evaluation/cii_best_practices_test.go index d1798bfa72b..50b15ad1b5f 100644 --- a/checks/evaluation/cii_best_practices_test.go +++ b/checks/evaluation/cii_best_practices_test.go @@ -16,71 +16,136 @@ package evaluation import ( "testing" - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" + sce "github.com/ossf/scorecard/v4/errors" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/hasOpenSSFBadge" + scut "github.com/ossf/scorecard/v4/utests" ) 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) + t.Parallel() + tests := []struct { + name string + findings []finding.Finding + result scut.TestReturn + }{ + { + name: "Unsupported badge found with negative finding", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomeNegative, + Values: map[string]int{ + "Unsupported": 1, + }, + }, + }, + result: scut.TestReturn{ + Score: 0, + }, + }, + { + name: "Unsupported badge found with positive finding", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + "Unsupported": 1, + }, + }, + }, + result: scut.TestReturn{ + Score: -1, + Error: sce.ErrScorecardInternal, + }, + }, + { + name: "Has InProgress Badge", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + hasOpenSSFBadge.InProgressLevel: 1, + }, + }, + }, + result: scut.TestReturn{ + Score: 2, + }, + }, + { + name: "Has Passing Badge", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + hasOpenSSFBadge.PassingLevel: 1, + }, + }, + }, + result: scut.TestReturn{ + Score: 5, + }, + }, + { + name: "Has Silver Badge", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + hasOpenSSFBadge.SilverLevel: 1, + }, + }, + }, + result: scut.TestReturn{ + Score: 7, + }, + }, + { + name: "Has Gold Badge", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + hasOpenSSFBadge.GoldLevel: 1, + }, + }, + }, + result: scut.TestReturn{ + Score: 10, + }, + }, + { + name: "Has Unknown Badge", + findings: []finding.Finding{ + { + Probe: "hasOpenSSFBadge", + Outcome: finding.OutcomePositive, + Values: map[string]int{ + "Unknown": 1, + }, + }, + }, + result: scut.TestReturn{ + Score: -1, + Error: sce.ErrScorecardInternal, + }, + }, + } + for _, tt := range tests { + tt := tt // Parallel testing + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + dl := scut.TestDetailLogger{} + got := CIIBestPractices(tt.name, tt.findings, &dl) + if !scut.ValidateTestReturn(t, tt.name, &tt.result, &got, &dl) { + t.Errorf("got %v, expected %v", got, tt.result) } }) - }) + } } diff --git a/probes/entries.go b/probes/entries.go index f745fb7512c..b5600ebe7e2 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -36,6 +36,7 @@ import ( "github.com/ossf/scorecard/v4/probes/hasLicenseFile" "github.com/ossf/scorecard/v4/probes/hasLicenseFileAtTopDir" "github.com/ossf/scorecard/v4/probes/hasOSVVulnerabilities" + "github.com/ossf/scorecard/v4/probes/hasOpenSSFBadge" "github.com/ossf/scorecard/v4/probes/hasRecentCommits" "github.com/ossf/scorecard/v4/probes/issueActivityByProjectMember" "github.com/ossf/scorecard/v4/probes/notArchived" @@ -117,6 +118,9 @@ var ( issueActivityByProjectMember.Run, notCreatedRecently.Run, } + CIIBestPractices = []ProbeImpl{ + hasOpenSSFBadge.Run, + } ) //nolint:gochecknoinits diff --git a/probes/hasOpenSSFBadge/def.yml b/probes/hasOpenSSFBadge/def.yml new file mode 100644 index 00000000000..1b62af9d757 --- /dev/null +++ b/probes/hasOpenSSFBadge/def.yml @@ -0,0 +1,29 @@ +# 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: hasOpenSSFBadge +short: This check determines whether the project has an OpenSSF (formerly CII) Best Practices Badge. +motivation: > + The OpenSSF Best Practices badge indicates whether or not the project uses a set of security-focused best development practices for open source software. +implementation: > + The probe checks the type of the badge from the raw results. +outcome: + - If the project has a badge, the probe returns one OutcomePositive (1). The finding includes an entry in the `Values` map with the key describing the badge level. + - If the project does not have a badge, the probe returns one OutcomeNegative (0). +remediation: + effort: High + text: + - Learn about best practices by following [the OpenSSF Best Practices Badge criteria](https://www.bestpractices.dev/en/criteria/0). + markdown: + - Learn about best practices by following [the OpenSSF Best Practices Badge criteria](https://www.bestpractices.dev/en/criteria/0). diff --git a/probes/hasOpenSSFBadge/impl.go b/probes/hasOpenSSFBadge/impl.go new file mode 100644 index 00000000000..009326da535 --- /dev/null +++ b/probes/hasOpenSSFBadge/impl.go @@ -0,0 +1,80 @@ +// 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. + +//nolint:stylecheck +package hasOpenSSFBadge + +import ( + "embed" + "fmt" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + Probe = "hasOpenSSFBadge" + GoldLevel = "Gold" + SilverLevel = "Silver" + PassingLevel = "Passing" + InProgressLevel = "InProgress" + UnknownLevel = "Unknown" +) + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.CIIBestPracticesResults + var badgeLevel string + + switch r.Badge { + case clients.Gold: + badgeLevel = GoldLevel + case clients.Silver: + badgeLevel = SilverLevel + case clients.Passing: + badgeLevel = PassingLevel + case clients.InProgress: + badgeLevel = InProgressLevel + case clients.Unknown: + badgeLevel = UnknownLevel + default: + f, err := finding.NewWith(fs, Probe, + "Project does not have an OpenSSF badge", nil, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + return []finding.Finding{*f}, Probe, nil + } + + f, err := finding.NewWith(fs, Probe, + fmt.Sprintf("OpenSSF best practice badge found at %s level.", badgeLevel), + nil, finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + + f = f.WithValues(map[string]int{ + badgeLevel: 1, + }) + return []finding.Finding{*f}, Probe, nil +} diff --git a/probes/hasOpenSSFBadge/impl_test.go b/probes/hasOpenSSFBadge/impl_test.go new file mode 100644 index 00000000000..d4311d4de2b --- /dev/null +++ b/probes/hasOpenSSFBadge/impl_test.go @@ -0,0 +1,121 @@ +// 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. + +//nolint:stylecheck +package hasOpenSSFBadge + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "Has Gold badge", + raw: &checker.RawResults{ + CIIBestPracticesResults: checker.CIIBestPracticesData{ + Badge: clients.Gold, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Has Silver badge", + raw: &checker.RawResults{ + CIIBestPracticesResults: checker.CIIBestPracticesData{ + Badge: clients.Silver, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Has Passing badge", + raw: &checker.RawResults{ + CIIBestPracticesResults: checker.CIIBestPracticesData{ + Badge: clients.Passing, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Has InProgress badge", + raw: &checker.RawResults{ + CIIBestPracticesResults: checker.CIIBestPracticesData{ + Badge: clients.InProgress, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Has Unknown badge", + raw: &checker.RawResults{ + CIIBestPracticesResults: checker.CIIBestPracticesData{ + Badge: clients.Unknown, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} From fea2f45dd8ead4289f31c816e57b9c53c24fabc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:50:07 +0000 Subject: [PATCH 23/51] :seedling: Bump golang.org/x/oauth2 from 0.14.0 to 0.15.0 (#3697) Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.14.0 to 0.15.0. - [Commits](https://github.com/golang/oauth2/compare/v0.14.0...v0.15.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 456eec206c4..0ce0d7158be 100644 --- a/go.mod +++ b/go.mod @@ -106,7 +106,7 @@ require ( github.com/spdx/tools-golang v0.5.3 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/term v0.14.0 // indirect + golang.org/x/term v0.15.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/vuln v1.0.1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect @@ -172,12 +172,12 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - golang.org/x/crypto v0.15.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/oauth2 v0.14.0 + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 3acf5f1c25e..8db57a3df62 100644 --- a/go.sum +++ b/go.sum @@ -832,8 +832,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -917,15 +917,15 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -998,8 +998,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1008,8 +1008,8 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 3cbafa90122b18b92beaa68d6421d43b2f7cecec Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:59:35 +0000 Subject: [PATCH 24/51] :book: fix typo (#3699) Signed-off-by: Adam Korczynski --- probes/notArchived/def.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/probes/notArchived/def.yml b/probes/notArchived/def.yml index b5858c1388f..6d856ea2c63 100644 --- a/probes/notArchived/def.yml +++ b/probes/notArchived/def.yml @@ -13,7 +13,7 @@ # limitations under the License. id: notArchived -short: Check that the project is archvied +short: Check that the project is archived motivation: > A project which is not active might not be patched, have its dependencies patched, or be actively tested and used. However, a lack of active maintenance is not necessarily always a problem. Some software, especially smaller utility functions, does not normally need to be maintained. For example, a library that determines if an integer is even would not normally need maintenance unless an underlying implementation language definition changed. A lack of active maintenance should signal that potential users should investigate further to judge the situation. implementation: > @@ -24,4 +24,4 @@ outcome: remediation: effort: High text: - - Non-collaborators, members or owners cannot affect the outcome of this probe. \ No newline at end of file + - Non-collaborators, members or owners cannot affect the outcome of this probe. From 0e7e58a3692e57a74b72e744bb854718105b03cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:35:39 -0500 Subject: [PATCH 25/51] :seedling: Bump github.com/onsi/ginkgo/v2 from 2.13.1 to 2.13.2 (#3704) Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.1 to 2.13.2. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.1...v2.13.2) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0ce0d7158be..7bedadc5730 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/google/go-github/v53 v53.2.0 github.com/google/osv-scanner v1.4.3 github.com/mcuadros/go-jsonschema-generator v0.0.0-20200330054847-ba7a369d4303 - github.com/onsi/ginkgo/v2 v2.13.1 + github.com/onsi/ginkgo/v2 v2.13.2 github.com/otiai10/copy v1.14.0 sigs.k8s.io/release-utils v0.6.0 ) diff --git a/go.sum b/go.sum index 8db57a3df62..add4801a4c7 100644 --- a/go.sum +++ b/go.sum @@ -622,8 +622,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= -github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= +github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= +github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= From ce0b54efe0bec8d44a0eae8846d3a5fc5f3c9ef9 Mon Sep 17 00:00:00 2001 From: ariathaker <51683211+ariathaker@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:17:56 -0800 Subject: [PATCH 26/51] =?UTF-8?q?=F0=9F=93=96=20Add=20beginner's=20guide?= =?UTF-8?q?=20to=20scorecard=20checks=20docs=20(#3617)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * -Added beginner's guide to scorecard checks doc -Edited README to link to the beginner's guide Signed-off-by: ariathaker * Update beginner-checks.md Incorporating Spencer's edits. Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update docs/beginner-checks.md Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update docs/beginner-checks.md Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update docs/beginner-checks.md Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update docs/beginner-checks.md Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update docs/beginner-checks.md Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update docs/beginner-checks.md Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update beginner-checks.md Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Signed-off-by: ariathaker * Update beginner-checks.md Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> * Update beginner-checks.md Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> * Update beginner-checks.md Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> * Update beginner-checks.md Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> --------- Signed-off-by: ariathaker Signed-off-by: ariathaker <51683211+ariathaker@users.noreply.github.com> Co-authored-by: olivekl <83081275+olivekl@users.noreply.github.com> --- README.md | 17 +++++---- docs/beginner-checks.md | 76 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 docs/beginner-checks.md diff --git a/README.md b/README.md index bda6efed521..b876a764dae 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ - [Default Scorecard Checks](#scorecard-checks) - [Detailed Check Documentation](docs/checks.md) (Scoring Criteria, Risks, and Remediation) +- [Beginner's Guide to Scorecard Checks](#beginners-guide-to-scorecard-checks) ## Other Important Recommendations - [Two-factor Authentication (2FA)](#two-factor-authentication-2fa) @@ -94,14 +95,14 @@ metrics. Prominent projects that use Scorecard include: ### View a Project's Score -To see scores for projects regularly scanned by Scorecard, navigate to the webviewer, replacing the placeholder text with the platform, user/org, and repository name: +To see scores for projects regularly scanned by Scorecard, navigate to the webviewer, replacing the placeholder text with the platform, user/org, and repository name: https://securityscorecards.dev/viewer/?uri=.com//. -For example: +For example: - [https://securityscorecards.dev/viewer/?uri=github.com/ossf/scorecard](https://securityscorecards.dev/viewer/?uri=github.com/ossf/scorecard) - [https://securityscorecards.dev/viewer/?uri=gitlab.com/fdroid/fdroidclient](https://securityscorecards.dev/viewer/?uri=gitlab.com/fdroid/fdroidclient) -To view scores for projects not included in the webviewer, use the [Scorecard CLI](#scorecard-command-line-interface). +To view scores for projects not included in the webviewer, use the [Scorecard CLI](#scorecard-command-line-interface). ### Public Data @@ -506,6 +507,10 @@ Name | Description | Risk Level | Token Req To see detailed information about each check, its scoring criteria, and remediation steps, check out the [checks documentation page](docs/checks.md). +### Beginner's Guide to Scorecard Checks + +For a guide to the checks you should use when getting started, see the [beginner's guide to scorecard checks](docs/beginner-checks.md). + ## Other Important Recommendations ### Two-factor Authentication (2FA) @@ -593,13 +598,13 @@ To report a security issue, please follow instructions [here](SECURITY.md). ### Join the Scorecards Project Meeting -#### Zoom +#### Zoom -We meet every other Thursday - 4p ET on this [zoom link](https://zoom.us/j/98835923979?pwd=RG5JZ3czZEtmRDlGdms0ZktmMFQvUT09). +We meet every other Thursday - 4p ET on this [zoom link](https://zoom.us/j/98835923979?pwd=RG5JZ3czZEtmRDlGdms0ZktmMFQvUT09). #### Agenda -You can see the [agenda and meeting notes here](https://docs.google.com/document/d/1b6d3CVJLsl7YnTE7ZaZQHdkdYIvuOQ8rzAmvVdypOWM/edit?usp=sharing). +You can see the [agenda and meeting notes here](https://docs.google.com/document/d/1b6d3CVJLsl7YnTE7ZaZQHdkdYIvuOQ8rzAmvVdypOWM/edit?usp=sharing). ## Stargazers over time diff --git a/docs/beginner-checks.md b/docs/beginner-checks.md new file mode 100644 index 00000000000..dfca3765a53 --- /dev/null +++ b/docs/beginner-checks.md @@ -0,0 +1,76 @@ +# Getting Started with Scorecard Checks for Supply Chain Security + +Choosing which Scorecard checks to get started with as a project maintainer can be overwhelming. This page walks through some of the most important checks to start with for project improvement, focusing on the ones that give you the biggest payoff versus effort. They're broken down into three categories based on stages of the development process: [setting up your project](#1-setting-up-your-project), [accepting contributions from others](#2-manage-contributions-to-your-project), and [packaging the project to release to the world](#3-package-and-release-your-project). + +Note: not every Scorecard check or topic mentioned on this page might be relevant to your project. See below for more on [customizing your checks to your needs](#customize-your-checks-to-your-projects-needs). + +## 1. Setting up your project + +Start your project off strong by focusing on Scorecard checks that help you secure your project dependencies and workflows. + +- Secure your dependencies with the Vulnerabilities check and the Dependency-Update-Tool check +- Secure your workflows with the Token-Permissions check + +### The Vulnerabilities and Dependency-Update-Tool checks secure your dependencies + +Vulnerabilities are probably the most familiar security risk. By running Scorecard’s [Vulnerabilities check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#vulnerabilities), you’ll get information about known vulnerabilities in your project, either through your codebase or through your direct and (for most languages) indirect dependencies. Tracking vulnerabilities in an indirect (sometimes called transitive) dependency can be tricky, but it’s important: [95% of vulnerable dependencies are transitive](https://www.endorlabs.com/state-of-dependency-management). + +If vulnerabilities are found in your dependencies, there are a few options: + +- Update the dependency to a non-vulnerable version (if available) +- Submit a patch to the vulnerable project +- Replace the dependency with a non-vulnerable dependency +- Remove the dependency and write code to take its place +- If you are sure a vulnerability does not impact your project, you may ignore the dependency by creating an [osv-scanner.toml](https://google.github.io/osv-scanner/configuration/#ignore-vulnerabilities-by-id) file in your project's root directory. + +If you have handled the vulnerabilities in your dependencies and are still not satisfied with your score for this check, make sure there are no open, unfixed vulnerabilities in your project’s own codebase. Once you have dealt with those, your score should improve. + +Next, Scorecard’s [Dependency-Update-Tool check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#dependency-update-tool) encourages developers to keep their dependencies up to date, which is a great way to stay on top of security updates. This check awards a high score to a project if it uses a dependency update tool such as [Dependabot](https://docs.github.com/code-security/dependabot), [Renovate bot](https://docs.renovatebot.com/), or [PyUp](https://github.com/pyupio/pyup#readme). Using one of these tools helps streamline security processes by notifying you when vulnerabilities have surfaced in your dependencies or when new versions of your dependencies become available. + +Automated processes like these save you time and are highly configurable; for example, you can set your bot to update dependencies every day or every week at the same time. + +If you want to increase your score in this category, sign up for automatic updates with a dependency update tool. Keep in mind, though, that this check can only show that the dependency update tool is enabled, not that it is running. To benefit as much as possible from this check, be sure that you consistently run and act on the information from your dependency update tool. + +### Token-Permissions check helps you secure your workflows + +We suggest addressing the [Token-Permissions check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions) next because it takes just a few minutes to “set it and forget it” and secure your workflows. The check warns you when your project’s top-level tokens have `write` access instead of the more restrictive `read` access. Not all `write` access permissions need to be eliminated; some workflows may genuinely require them. But ensuring your top-level permissions have `read` access helps your project follow the principle of least privilege, which means that permissions are granted based on the minimal necessary access to perform a function. Projects that have top-level tokens set to `write` are granting more access than necessary to their automated workflow dependencies. If those dependencies were ever compromised, they could become an attack vector, and could be vulnerable to malicious code execution. + +To change the default setting for token permissions, add the following to the top of your workflow: + +``` +permissions: + contents: read +``` + +When you add a GitHub Action, be sure to read the Action’s docs to see if it needs any additional permissions; this information is usually prominent in the Action’s README. + +## 2. Manage contributions to your project + +As projects grow, they generally start including contributions from others. Contributors can expand your project’s scope and maturity, but they can also introduce security risk. To protect your project at this stage, we recommend improving the Branch Protection check, which allows you, the maintainer, to define rules that require certain workflows for certain branches. + +### Branch Protection reduces the risks of errors and hacks + +The [Branch Protection check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection) can help protect your code from unvetted changes. You can choose either or both of the following options: + +- Require code review. Select this if your project has more than one maintainer. Requiring review before changes are merged is one of the strongest protections you can give your code. This will also improve your [Code Review check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#code-review) score. +- Require [status checks](https://docs.github.com/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks). All projects would benefit from selecting this option. It ensures that all Continuous Integration (CI) tests chosen by the maintainer have passed before a change is accepted, helping you catch mistakes early on in the development process. This will also improve your [CI Test check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#ci-tests) score. + +## 3. Package and release your project + +Deciding how to securely share your code can be difficult. Building locally on your laptop may seem simpler at first, but using an automated build process to create your package on your CI/CD system provides you with security benefits that pay off in the long run. Scorecard’s Packaging check helps guide you through this process. + +### Packaging check verifies if a project is published as a package + +The [Packaging check](https://github.com/ossf/scorecard/blob/main/docs/checks.md#packaging) assesses whether a project has been published as a package. The check is currently limited to repositories hosted on GitHub. It looks for [GitHub packaging workflows](https://docs.github.com/packages/learn-github-packages/publishing-a-package) and language-specific GitHub Actions that upload the package to a corresponding hub, like npm or PyPI. + +Another benefit to releasing projects as packages is reproducibility—the version that new users can download and execute is identical to the one that you and other contributors have already reviewed. Packages also have clear versioning documentation that makes it easier to track whether any newly discovered security issues are applicable to your project. + +Packaging your projects makes it easier for users to receive security patches as updates. It also provides information about the release details to your users, which opens the door to more collaboration from your open-source peers. + +## Customize your checks to your project’s needs + +Based on the specifics of your project, not all the checks offered by Scorecard or discussed on this page may apply to you. For example, if you are the sole maintainer of an open-source project, the “Code Review” check would not be usable for your project. + +The languages you use also influence which checks will be useful to you. For example, if your project is built in C or C++, the Packaging and Dependency-Update-Tool checks will not be applicable because the C/C++ ecosystem does not have a centralized package manager. + +To learn more about all the checks Scorecard offers, see the [checks documentation](https://github.com/ossf/scorecard/blob/main/docs/checks.md#check-documentation). From 0c40e14b75a865ff030e9b4884bdc97b1eac3e64 Mon Sep 17 00:00:00 2001 From: Martin Costello Date: Thu, 30 Nov 2023 19:26:47 +0000 Subject: [PATCH 27/51] :bug: Trust pinned GitHub download URLs (#3694) * Trust pinned GitHub download URLs Trust files that are downloaded from `raw.githubusercontent.com` where the file's ref is a Git SHA and therefore immutable. Resolves #3339. Signed-off-by: martincostello * Move logic to function - Add `hasUnpinnedURLs` function. - Add test cases for different URLs. Signed-off-by: martincostello * Fix formatting Appease the linter. Signed-off-by: martincostello * Suppress lint warnings Suppress warning on three long URLs. Signed-off-by: martincostello * Address peer review Address peer review feedback. Signed-off-by: martincostello * Fix lint warning Fix lint warning. Signed-off-by: martincostello --- checks/raw/pinned_dependencies_test.go | 42 +++++- checks/raw/shell_download_validate.go | 36 +++++ checks/raw/shell_download_validate_test.go | 128 ++++++++++++++++++ checks/raw/testdata/Dockerfile-curl-sh | 6 + checks/raw/testdata/Dockerfile-download-lines | 10 +- checks/raw/testdata/Dockerfile-wget-bin-sh | 6 + checks/raw/testdata/script-bash | 9 ++ checks/raw/testdata/shell-download-lines.sh | 8 +- 8 files changed, 240 insertions(+), 5 deletions(-) diff --git a/checks/raw/pinned_dependencies_test.go b/checks/raw/pinned_dependencies_test.go index bc755c8dba1..3800006d9c0 100644 --- a/checks/raw/pinned_dependencies_test.go +++ b/checks/raw/pinned_dependencies_test.go @@ -728,6 +728,24 @@ func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { endLine: 64, t: checker.DependencyUseTypePipCommand, }, + { + snippet: `bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash")`, + startLine: 68, + endLine: 68, + t: checker.DependencyUseTypeDownloadThenRun, + }, + { + snippet: "curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin", + startLine: 69, + endLine: 69, + t: checker.DependencyUseTypeDownloadThenRun, + }, + { + snippet: "curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | bash /dev/stdin", + startLine: 70, + endLine: 70, + t: checker.DependencyUseTypeDownloadThenRun, + }, }, }, { @@ -975,6 +993,24 @@ func TestShellscriptInsecureDownloadsLineNumber(t *testing.T) { endLine: 64, t: checker.DependencyUseTypeNugetCommand, }, + { + snippet: `bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash")`, + startLine: 69, + endLine: 69, + t: checker.DependencyUseTypeDownloadThenRun, + }, + { + snippet: "curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin", + startLine: 70, + endLine: 70, + t: checker.DependencyUseTypeDownloadThenRun, + }, + { + snippet: "curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | bash /dev/stdin", + startLine: 71, + endLine: 71, + t: checker.DependencyUseTypeDownloadThenRun, + }, }, }, } @@ -1079,7 +1115,7 @@ func TestDockerfileScriptDownload(t *testing.T) { { name: "curl | sh", filename: "./testdata/Dockerfile-curl-sh", - unpinned: 4, + unpinned: 5, }, { name: "empty file", @@ -1096,7 +1132,7 @@ func TestDockerfileScriptDownload(t *testing.T) { { name: "wget | /bin/sh", filename: "./testdata/Dockerfile-wget-bin-sh", - unpinned: 3, + unpinned: 4, }, { name: "wget no exec", @@ -1262,7 +1298,7 @@ func TestShellScriptDownload(t *testing.T) { { name: "bash script", filename: "./testdata/script-bash", - unpinned: 7, + unpinned: 11, }, { name: "sh script 2", diff --git a/checks/raw/shell_download_validate.go b/checks/raw/shell_download_validate.go index d5fd530142e..b2149bbf656 100644 --- a/checks/raw/shell_download_validate.go +++ b/checks/raw/shell_download_validate.go @@ -57,6 +57,8 @@ var downloadUtils = []string{ "curl", "wget", "gsutil", } +var gitCommitHashRegex = regexp.MustCompile(`^[a-fA-F0-9]{40}$`) + func isBinaryName(expected, name string) bool { return strings.EqualFold(path.Base(name), expected) } @@ -296,6 +298,36 @@ func getLine(startLine, endLine uint, node syntax.Node) (uint, uint) { startLine + node.Pos().Line() } +func hasUnpinnedURLs(cmd []string) bool { + var urls []*url.URL + + // Extract any URLs passed to the download utility + for _, s := range cmd { + u, err := url.ParseRequestURI(s) + if err == nil { + urls = append(urls, u) + } + } + + // Look for any URLs which are pinned to a GitHub SHA + var pinned []*url.URL + for _, u := range urls { + // Look for a URL of the form: https://raw.githubusercontent.com/{owner}/{repo}/{ref}/{path} + if u.Scheme == "https" && u.Host == "raw.githubusercontent.com" { + segments := strings.Split(u.Path, "/") + if len(segments) > 4 && gitCommitHashRegex.MatchString(segments[3]) { + pinned = append(pinned, u) + } + } + } + + if len(pinned) > 0 && len(urls) == len(pinned) { + return false + } + + return true +} + func collectFetchPipeExecute(startLine, endLine uint, node syntax.Node, cmd, pathfn string, r *checker.PinningDependenciesData, ) { @@ -327,6 +359,10 @@ func collectFetchPipeExecute(startLine, endLine uint, node syntax.Node, cmd, pat return } + if !hasUnpinnedURLs(leftStmt) { + return + } + startLine, endLine = getLine(startLine, endLine, node) r.Dependencies = append(r.Dependencies, diff --git a/checks/raw/shell_download_validate_test.go b/checks/raw/shell_download_validate_test.go index d1982216a26..e7f615cac7a 100644 --- a/checks/raw/shell_download_validate_test.go +++ b/checks/raw/shell_download_validate_test.go @@ -312,3 +312,131 @@ func Test_isNpmUnpinnedDownload(t *testing.T) { }) } } + +func Test_hasUnpinnedURLs(t *testing.T) { + t.Parallel() + type args struct { + cmd []string + } + tests := []struct { + name string + args args + expected bool + }{ + { + name: "Unpinned URL", + args: args{ + cmd: []string{ + "curl", + "-sSL", + "https://dot.net/v1/dotnet-install.sh", + }, + }, + expected: true, + }, + { + name: "GitHub content URL but no path", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "https://raw.githubusercontent.com", + }, + }, + expected: true, + }, + { + name: "GitHub content URL but no ref", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "https://raw.githubusercontent.com/dotnet/install-scripts", + }, + }, + expected: true, + }, + { + name: "Unpinned GitHub content URL", + args: args{ + cmd: []string{ + "curl", + "-sSL", + "https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh", + }, + }, + expected: true, + }, + { + name: "Pinned GitHub content URL but invalid SHA", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "https://raw.githubusercontent.com/dotnet/install-scripts/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/src/dotnet-install.sh", //nolint:lll + }, + }, + expected: true, + }, + { + name: "Pinned GitHub content URL but no file path", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85", + }, + }, + expected: true, + }, + { + name: "Pinned GitHub content URL", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", //nolint:lll + }, + }, + expected: false, + }, + { + name: "Pinned GitHub content URL but HTTP", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "http://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", //nolint:lll + }, + }, + expected: true, + }, + { + name: "Pinned GitHub URL but not raw content", + args: args{ + cmd: []string{ + "wget", + "-0", + "-", + "https://github.com/dotnet/install-scripts/blob/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", + }, + }, + expected: true, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if actual := hasUnpinnedURLs(tt.args.cmd); actual != tt.expected { + t.Errorf("hasUnpinnedURLs() = %v, expected %v for %v", actual, tt.expected, tt.name) + } + }) + } +} diff --git a/checks/raw/testdata/Dockerfile-curl-sh b/checks/raw/testdata/Dockerfile-curl-sh index e80a7e194dc..19a9ab0dfac 100644 --- a/checks/raw/testdata/Dockerfile-curl-sh +++ b/checks/raw/testdata/Dockerfile-curl-sh @@ -20,5 +20,11 @@ RUN echo hello && curl -s file-with-sudo2 | sudo bash RUN echo hello && sudo curl -s file-with-sudo | bash | bla RUN ["echo", "hello", "&&", "curl", "-s", "/etc/file2", "|", "sh"] +# Unpinned +RUN curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | bash /dev/stdin + +# Pinned +RUN curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh | bash /dev/stdin + FROM scratch FROM python@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2 \ No newline at end of file diff --git a/checks/raw/testdata/Dockerfile-download-lines b/checks/raw/testdata/Dockerfile-download-lines index 17bba340329..386dc20f427 100644 --- a/checks/raw/testdata/Dockerfile-download-lines +++ b/checks/raw/testdata/Dockerfile-download-lines @@ -62,4 +62,12 @@ RUN pip install --no-deps -e . git+https://github.com/username/repo.git RUN pip install --no-deps -e . git+https://github.com/username/repo.git@0123456789abcdef0123456789abcdef01234567#egg=package RUN python -m pip install --no-deps -e git+https://github.com/username/repo.git -RUN python -m pip install --no-deps -e git+https://github.com/username/repo.git@0123456789abcdef0123456789abcdef01234567#egg=package \ No newline at end of file +RUN python -m pip install --no-deps -e git+https://github.com/username/repo.git@0123456789abcdef0123456789abcdef01234567#egg=package + +# Unpinned +RUN bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash") +RUN curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin +RUN curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | bash /dev/stdin +# Pinned +RUN bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/7b75d16d41920ec126e6f3269db0c6f3ab613c38/scripts/download-actionlint.bash") +RUN curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh | bash /dev/stdin \ No newline at end of file diff --git a/checks/raw/testdata/Dockerfile-wget-bin-sh b/checks/raw/testdata/Dockerfile-wget-bin-sh index f97b4c33b54..61988b99999 100644 --- a/checks/raw/testdata/Dockerfile-wget-bin-sh +++ b/checks/raw/testdata/Dockerfile-wget-bin-sh @@ -19,5 +19,11 @@ RUN echo hello && wget -0 - http://ifconfig.co/json | /bin/sh RUN ["echo", "hello", "&&", "wget", "-0", "-", "http://ifconfig.co/json", "|", "/bin/sh"] RUN ["sh", "-c", "\"wget -0 - http://ifconfig.co/json | /bin/sh\""] +# Unpinned +RUN wget -0 - https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | /bin/sh + +# Pinned +RUN wget -0 - https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh | /bin/sh + FROM scratch FROM python@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2 \ No newline at end of file diff --git a/checks/raw/testdata/script-bash b/checks/raw/testdata/script-bash index 4603ac2e16e..1f04dce38f1 100644 --- a/checks/raw/testdata/script-bash +++ b/checks/raw/testdata/script-bash @@ -49,4 +49,13 @@ bash <(wget -qO- http://website.com/my-script.sh) wget http://file-with-sudo -O /tmp/file3 bash /tmp/file3 +bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash") +curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin +curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | bash /dev/stdin +RUN bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/7b75d16d41920ec126e6f3269db0c6f3ab613c38/scripts/download-actionlint.bash") +RUN curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh | bash /dev/stdin + +wget https://dot.net/v1/dotnet-install.sh -O /tmp/file4 +bash /tmp/file4 + date \ No newline at end of file diff --git a/checks/raw/testdata/shell-download-lines.sh b/checks/raw/testdata/shell-download-lines.sh index 6a4f934e726..2bc7bdeabd8 100644 --- a/checks/raw/testdata/shell-download-lines.sh +++ b/checks/raw/testdata/shell-download-lines.sh @@ -64,4 +64,10 @@ dotnet add package some-package dotnet add SomeProject package some-package dotnet build dotnet add package some-package -v 1.2.3 -dotnet add package some-package --version 1.2.3 \ No newline at end of file +dotnet add package some-package --version 1.2.3 + +bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash") +curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin +curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.sh | bash /dev/stdin +RUN bash <(curl --silent --show-error "https://raw.githubusercontent.com/rhysd/actionlint/7b75d16d41920ec126e6f3269db0c6f3ab613c38/scripts/download-actionlint.bash") +RUN curl -sSL https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh | bash /dev/stdin \ No newline at end of file From 4d1621b92e774dd1ae965b0011a54d6ba54ae905 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:45:41 +0000 Subject: [PATCH 28/51] :seedling: Bump github.com/google/go-containerregistry (#3708) Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.16.1 to 0.17.0. - [Release notes](https://github.com/google/go-containerregistry/releases) - [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml) - [Commits](https://github.com/google/go-containerregistry/compare/v0.16.1...v0.17.0) --- updated-dependencies: - dependency-name: github.com/google/go-containerregistry dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7bedadc5730..0b304f864e8 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/go-logr/logr v1.3.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 - github.com/google/go-containerregistry v0.16.1 + github.com/google/go-containerregistry v0.17.0 github.com/grafeas/kritis v0.2.3-0.20210120183821-faeba81c520c github.com/h2non/filetype v1.1.3 github.com/jszwec/csvutil v1.8.0 diff --git a/go.sum b/go.sum index add4801a4c7..026b5204e92 100644 --- a/go.sum +++ b/go.sum @@ -394,8 +394,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.2.1/go.mod h1:Ts3Wioz1r5ayWx8sS6vLcWltWcM1aqFjd/eVrkFhrWM= -github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= -github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk= +github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= github.com/google/go-github/v56 v56.0.0 h1:TysL7dMa/r7wsQi44BjqlwaHvwlFlqkK8CtBWCX3gb4= From 1625b0c578e682857394fb0bbef6ad1861b7acac Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Sun, 3 Dec 2023 18:14:01 -0800 Subject: [PATCH 29/51] :seedling: Disable more style linters for test files (#3707) * disable lll linter for test files * disable goerr113 linter for tests * disable wrapcheck linter for tests * fix easy linter issues in tests --------- Signed-off-by: Spencer Schrock --- .golangci.yml | 3 ++ checker/check_result_test.go | 6 +-- checker/client_test.go | 2 +- checks/ci_tests_test.go | 1 - checks/code_review_test.go | 1 - checks/contributors_test.go | 2 +- checks/evaluation/ci_tests_test.go | 6 ++- checks/fileparser/listing_test.go | 1 - checks/fuzzing_test.go | 2 - checks/maintained_test.go | 2 +- checks/permissions_test.go | 1 - checks/raw/fuzzing_test.go | 3 -- checks/raw/gitlab/packaging_test.go | 11 ++--- checks/raw/maintained_test.go | 8 ++-- checks/raw/pinned_dependencies_test.go | 10 ++--- checks/raw/vulnerabilities_test.go | 6 +-- checks/sast_test.go | 2 +- checks/signed_releases_test.go | 4 +- clients/git/client_test.go | 4 +- clients/githubrepo/copy_test.go | 10 ++--- .../roundtripper/tokens/accessor_test.go | 6 --- clients/githubrepo/webhook_test.go | 1 - clients/gitlabrepo/branches_test.go | 9 ++-- clients/gitlabrepo/issues_test.go | 1 - clients/gitlabrepo/webhook_test.go | 1 - cmd/internal/nuget/client_test.go | 6 --- cmd/internal/scdiff/app/compare_test.go | 2 - cmd/internal/scdiff/app/generate_test.go | 1 - cmd/package_managers_test.go | 7 --- cron/config/config_test.go | 1 - cron/internal/pubsub/publisher_test.go | 1 - .../pubsub/subscriber_gocloud_test.go | 6 +-- e2e/attestor_policy_test.go | 2 +- errors/internal_test.go | 4 +- errors/public_test.go | 2 +- options/flags_test.go | 2 +- pkg/json_raw_results_test.go | 45 +++++++++---------- pkg/json_test.go | 2 +- pkg/scorecard_e2e_test.go | 2 +- probes/hasOSVVulnerabilities/impl_test.go | 2 - remediation/remediations_test.go | 3 +- 41 files changed, 76 insertions(+), 115 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b4b4e505264..350c4328101 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -18,6 +18,9 @@ issues: - funlen - goconst - gocyclo + - goerr113 + - lll + - wrapcheck skip-files: - cron/data/request.pb.go # autogenerated linters: diff --git a/checker/check_result_test.go b/checker/check_result_test.go index 42cc8a66823..cf792232704 100644 --- a/checker/check_result_test.go +++ b/checker/check_result_test.go @@ -545,7 +545,7 @@ func TestCreateProportionalScoreResult(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CreateProportionalScoreResult(tt.args.name, tt.args.reason, tt.args.b, tt.args.t); !cmp.Equal(got, tt.want) { //nolint:lll + if got := CreateProportionalScoreResult(tt.args.name, tt.args.reason, tt.args.b, tt.args.t); !cmp.Equal(got, tt.want) { t.Errorf("CreateProportionalScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) } }) @@ -714,14 +714,14 @@ func TestCreateRuntimeErrorResult(t *testing.T) { name: "empty", args: args{ name: "", - e: errors.New("runtime error"), //nolint:goerr113 + e: errors.New("runtime error"), }, want: CheckResult{ Name: "", Reason: "runtime error", Score: -1, Version: 2, - Error: errors.New("runtime error"), //nolint:goerr113 + Error: errors.New("runtime error"), }, }, } diff --git a/checker/client_test.go b/checker/client_test.go index c1caf79cf13..9426e841bdb 100644 --- a/checker/client_test.go +++ b/checker/client_test.go @@ -106,7 +106,7 @@ func TestGetClients(t *testing.T) { t.Setenv("GH_HOST", "github.corp.com") t.Setenv("GH_TOKEN", "PAT") } - got, repoClient, ossFuzzClient, ciiClient, vulnsClient, err := GetClients(tt.args.ctx, tt.args.repoURI, tt.args.localURI, tt.args.logger) //nolint:lll + got, repoClient, ossFuzzClient, ciiClient, vulnsClient, err := GetClients(tt.args.ctx, tt.args.repoURI, tt.args.localURI, tt.args.logger) if (err != nil) != tt.wantErr { t.Fatalf("GetClients() error = %v, wantErr %v", err, tt.wantErr) } diff --git a/checks/ci_tests_test.go b/checks/ci_tests_test.go index 8e19820e3c2..7acb4bb1810 100644 --- a/checks/ci_tests_test.go +++ b/checks/ci_tests_test.go @@ -29,7 +29,6 @@ func TestCITestsRuntimeError(t *testing.T) { ctrl := gomock.NewController(t) mockRepoClient := mockrepo.NewMockRepoClient(ctrl) - //nolint:goerr113 mockRepoClient.EXPECT().ListCommits().Return(nil, fmt.Errorf("some runtime error")).AnyTimes() req := checker.CheckRequest{ diff --git a/checks/code_review_test.go b/checks/code_review_test.go index 81d5d3675ad..1a384c6bd9e 100644 --- a/checks/code_review_test.go +++ b/checks/code_review_test.go @@ -30,7 +30,6 @@ import ( // TestCodeReview tests the code review checker. func TestCodereview(t *testing.T) { t.Parallel() - //nolint:goerr113 tests := []struct { err error name string diff --git a/checks/contributors_test.go b/checks/contributors_test.go index 9c162cff339..2ab795374c4 100644 --- a/checks/contributors_test.go +++ b/checks/contributors_test.go @@ -143,7 +143,7 @@ func TestContributors(t *testing.T) { }, }, { - err: errors.New("error"), //nolint:goerr113 + err: errors.New("error"), name: "Error getting contributors", contrib: []clients.User{}, expected: checker.CheckResult{ diff --git a/checks/evaluation/ci_tests_test.go b/checks/evaluation/ci_tests_test.go index 22ddae1e14b..19e20d3668c 100644 --- a/checks/evaluation/ci_tests_test.go +++ b/checks/evaluation/ci_tests_test.go @@ -192,8 +192,10 @@ func Test_prHasSuccessfulCheck(t *testing.T) { tt := tt dl := &scut.TestDetailLogger{} - //nolint:errcheck - got, _ := prHasSuccessfulCheck(tt.args, dl) + got, err := prHasSuccessfulCheck(tt.args, dl) + if err != nil { + t.Fatalf("unexpected err: %v", err) + } if got != tt.want { t.Errorf("prHasSuccessfulCheck() = %v, want %v", got, tt.want) } diff --git a/checks/fileparser/listing_test.go b/checks/fileparser/listing_test.go index 86bbc74d0e0..bb4e619b7aa 100644 --- a/checks/fileparser/listing_test.go +++ b/checks/fileparser/listing_test.go @@ -515,7 +515,6 @@ func TestOnMatchingFileContent(t *testing.T) { t.Parallel() x := func(path string, content []byte, args ...interface{}) (bool, error) { if tt.shouldFuncFail { - //nolint:goerr113 return false, errors.New("test error") } if tt.shouldGetPredicateFail { diff --git a/checks/fuzzing_test.go b/checks/fuzzing_test.go index ca909758ea4..c4f9a3f3f32 100644 --- a/checks/fuzzing_test.go +++ b/checks/fuzzing_test.go @@ -139,7 +139,6 @@ func TestFuzzing(t *testing.T) { mockFuzz.EXPECT().Search(gomock.Any()). DoAndReturn(func(q clients.SearchRequest) (clients.SearchResponse, error) { if tt.wantErr { - //nolint:goerr113 return clients.SearchResponse{}, errors.New("error") } return tt.response, nil @@ -148,7 +147,6 @@ func TestFuzzing(t *testing.T) { mockFuzz.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() mockFuzz.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) (string, error) { if tt.wantErr { - //nolint:goerr113 return "", errors.New("error") } return tt.fileContent, nil diff --git a/checks/maintained_test.go b/checks/maintained_test.go index d9fb337ae67..d47696e26e5 100644 --- a/checks/maintained_test.go +++ b/checks/maintained_test.go @@ -44,7 +44,7 @@ func Test_Maintained(t *testing.T) { otheruser := clients.User{ Login: "someone-else", } - //nolint:govet,goerr113 + //nolint:govet tests := []struct { err error name string diff --git a/checks/permissions_test.go b/checks/permissions_test.go index 0e72315608c..9261fb2792d 100644 --- a/checks/permissions_test.go +++ b/checks/permissions_test.go @@ -28,7 +28,6 @@ import ( scut "github.com/ossf/scorecard/v4/utests" ) -//nolint:lll func TestGithubTokenPermissions(t *testing.T) { t.Parallel() diff --git a/checks/raw/fuzzing_test.go b/checks/raw/fuzzing_test.go index d69430d8995..e409b401447 100644 --- a/checks/raw/fuzzing_test.go +++ b/checks/raw/fuzzing_test.go @@ -76,7 +76,6 @@ func Test_checkOSSFuzz(t *testing.T) { mockFuzz.EXPECT().Search(gomock.Any()). DoAndReturn(func(q clients.SearchRequest) (clients.SearchResponse, error) { if tt.wantErr { - //nolint:goerr113 return clients.SearchResponse{}, errors.New("error") } return tt.response, nil @@ -138,7 +137,6 @@ func Test_checkCFLite(t *testing.T) { mockFuzz.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() mockFuzz.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) (string, error) { if tt.wantErr { - //nolint:goerr113 return "", errors.New("error") } return tt.fileContent, nil @@ -490,7 +488,6 @@ func Test_checkFuzzFunc(t *testing.T) { mockClient.EXPECT().ListFiles(gomock.Any()).Return(tt.fileName, nil).AnyTimes() mockClient.EXPECT().GetFileContent(gomock.Any()).DoAndReturn(func(f string) ([]byte, error) { if tt.wantErr { - //nolint:goerr113 return nil, errors.New("error") } return []byte(tt.fileContent), nil diff --git a/checks/raw/gitlab/packaging_test.go b/checks/raw/gitlab/packaging_test.go index d300d20a62d..1e66f045200 100644 --- a/checks/raw/gitlab/packaging_test.go +++ b/checks/raw/gitlab/packaging_test.go @@ -136,9 +136,8 @@ func TestGitlabPackagingPackager(t *testing.T) { moqRepoClient.EXPECT().GetFileContent(tt.filename). DoAndReturn(func(b string) ([]byte, error) { - //nolint:errcheck - content, _ := os.ReadFile(b) - return content, nil + content, err := os.ReadFile(b) + return content, err }).AnyTimes() if tt.exists { @@ -150,8 +149,10 @@ func TestGitlabPackagingPackager(t *testing.T) { Repo: moqRepo, } - //nolint:errcheck - packagingData, _ := Packaging(&req) + packagingData, err := Packaging(&req) + if err != nil { + t.Fatalf("unexpected err: %v", err) + } if !tt.exists { if len(packagingData.Packages) != 0 { diff --git a/checks/raw/maintained_test.go b/checks/raw/maintained_test.go index 2df1ef7dd6f..2117175653a 100644 --- a/checks/raw/maintained_test.go +++ b/checks/raw/maintained_test.go @@ -78,7 +78,7 @@ func TestMaintained(t *testing.T) { }) t.Run("returns error if IsArchived fails", func(t *testing.T) { - mockRepoClient.EXPECT().IsArchived().Return(false, fmt.Errorf("some error")) //nolint:goerr113 + mockRepoClient.EXPECT().IsArchived().Return(false, fmt.Errorf("some error")) _, err := Maintained(req) if err == nil { @@ -88,7 +88,7 @@ func TestMaintained(t *testing.T) { t.Run("returns error if ListCommits fails", func(t *testing.T) { mockRepoClient.EXPECT().IsArchived().Return(false, nil) - mockRepoClient.EXPECT().ListCommits().Return(nil, fmt.Errorf("some error")) //nolint:goerr113 + mockRepoClient.EXPECT().ListCommits().Return(nil, fmt.Errorf("some error")) _, err := Maintained(req) if err == nil { @@ -99,7 +99,7 @@ func TestMaintained(t *testing.T) { t.Run("returns error if ListIssues fails", func(t *testing.T) { mockRepoClient.EXPECT().IsArchived().Return(false, nil) mockRepoClient.EXPECT().ListCommits().Return([]clients.Commit{}, nil) - mockRepoClient.EXPECT().ListIssues().Return(nil, fmt.Errorf("some error")) //nolint:goerr113 + mockRepoClient.EXPECT().ListIssues().Return(nil, fmt.Errorf("some error")) _, err := Maintained(req) if err == nil { @@ -111,7 +111,7 @@ func TestMaintained(t *testing.T) { mockRepoClient.EXPECT().IsArchived().Return(false, nil) mockRepoClient.EXPECT().ListCommits().Return([]clients.Commit{}, nil) mockRepoClient.EXPECT().ListIssues().Return([]clients.Issue{}, nil) - mockRepoClient.EXPECT().GetCreatedAt().Return(time.Time{}, fmt.Errorf("some error")) //nolint:goerr113 + mockRepoClient.EXPECT().GetCreatedAt().Return(time.Time{}, fmt.Errorf("some error")) _, err := Maintained(req) if err == nil { diff --git a/checks/raw/pinned_dependencies_test.go b/checks/raw/pinned_dependencies_test.go index 3800006d9c0..0eb2ea67c14 100644 --- a/checks/raw/pinned_dependencies_test.go +++ b/checks/raw/pinned_dependencies_test.go @@ -159,14 +159,12 @@ func TestGithubWorkflowPinningPattern(t *testing.T) { ispinned: true, }, { - desc: "non-github docker image pinned by digest", - //nolint:lll + desc: "non-github docker image pinned by digest", uses: "docker://gcr.io/distroless/static-debian11@sha256:9e6f8952f12974d088f648ed6252ea1887cdd8641719c8acd36bf6d2537e71c0", ispinned: true, }, { - desc: "non-github docker image pinned to mutable tag", - //nolint:lll + desc: "non-github docker image pinned to mutable tag", uses: "docker://gcr.io/distroless/static-debian11:sha256-3876708467ad6f38f263774aa107d331e8de6558a2874aa223b96fc0d9dfc820.sig", ispinned: false, }, @@ -635,7 +633,7 @@ func TestDockerfileInvalidFiles(t *testing.T) { func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { t.Parallel() - //nolint:govet,lll + //nolint:govet tests := []struct { name string filename string @@ -847,7 +845,7 @@ func TestDockerfileInsecureDownloadsLineNumber(t *testing.T) { func TestShellscriptInsecureDownloadsLineNumber(t *testing.T) { t.Parallel() - //nolint:govet,lll + //nolint:govet tests := []struct { name string filename string diff --git a/checks/raw/vulnerabilities_test.go b/checks/raw/vulnerabilities_test.go index 76da2f3514c..0df35e35557 100644 --- a/checks/raw/vulnerabilities_test.go +++ b/checks/raw/vulnerabilities_test.go @@ -47,9 +47,8 @@ func TestVulnerabilities(t *testing.T) { numberofCommits: 1, }, { - name: "err response", - wantErr: true, - //nolint:goerr113 + name: "err response", + wantErr: true, err: errors.New("error"), vulnsResponse: clients.VulnerabilitiesResponse{}, }, @@ -93,7 +92,6 @@ func TestVulnerabilities(t *testing.T) { mockVulnClient.EXPECT().ListUnfixedVulnerabilities(context.TODO(), gomock.Any(), gomock.Any()).DoAndReturn( func(ctx context.Context, commit string, localPath string) (clients.VulnerabilitiesResponse, error) { if tt.vulnsError { - //nolint:goerr113 return clients.VulnerabilitiesResponse{}, errors.New("error") } return tt.vulnsResponse, tt.err diff --git a/checks/sast_test.go b/checks/sast_test.go index 1f296fcdc13..05d95f1d94b 100644 --- a/checks/sast_test.go +++ b/checks/sast_test.go @@ -34,7 +34,7 @@ import ( func Test_SAST(t *testing.T) { t.Parallel() - //nolint:govet,goerr113 + //nolint:govet tests := []struct { name string err error diff --git a/checks/signed_releases_test.go b/checks/signed_releases_test.go index cfdaeaca355..39bdc017fb7 100644 --- a/checks/signed_releases_test.go +++ b/checks/signed_releases_test.go @@ -364,10 +364,10 @@ func TestSignedRelease(t *testing.T) { { name: "Error getting releases", - err: errors.New("Error getting releases"), //nolint:goerr113 + err: errors.New("Error getting releases"), expected: checker.CheckResult{ Score: -1, - Error: errors.New("Error getting releases"), //nolint:goerr113 + Error: errors.New("Error getting releases"), }, }, } diff --git a/clients/git/client_test.go b/clients/git/client_test.go index ce2d175fc34..483bad5977c 100644 --- a/clients/git/client_test.go +++ b/clients/git/client_test.go @@ -50,7 +50,7 @@ func createTestRepo(t *testing.T) (path string) { // Create a new file filePath := filepath.Join(dir, "file") - err = os.WriteFile(filePath, []byte("Hello, World!"), 0o644) //nolint:gosec + err = os.WriteFile(filePath, []byte("Hello, World!"), 0o600) if err != nil { t.Fatalf("Failed to write a file: %v", err) } @@ -185,7 +185,7 @@ func TestSearch(t *testing.T) { // Use the same test repo for all test cases. repoPath := createTestRepo(t) filePath := filepath.Join(repoPath, "test.txt") - err := os.WriteFile(filePath, []byte("Hello, World!"), 0o644) //nolint:gosec + err := os.WriteFile(filePath, []byte("Hello, World!"), 0o600) if err != nil { t.Fatalf("WriteFile() failed: %v", err) } diff --git a/clients/githubrepo/copy_test.go b/clients/githubrepo/copy_test.go index 73d3b8eacec..fe14f8c1aa9 100644 --- a/clients/githubrepo/copy_test.go +++ b/clients/githubrepo/copy_test.go @@ -53,7 +53,7 @@ func TestCopyBoolPtr(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() copyBoolPtr(tt.src, tt.dest) - if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && **tt.dest != *tt.want) { //nolint:lll + if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && **tt.dest != *tt.want) { t.Errorf("copyBoolPtr() got = %v, want %v", *tt.dest, tt.want) } }) @@ -103,7 +103,7 @@ func TestCopyInt32Ptr(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() copyInt32Ptr(tt.src, tt.dest) - if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && **tt.dest != *tt.want) { //nolint:lll + if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && **tt.dest != *tt.want) { t.Errorf("copyInt32Ptr() got = %v, want %v", *tt.dest, tt.want) } }) @@ -153,7 +153,7 @@ func TestCopyStringPtr(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() copyStringPtr(tt.src, tt.dest) - if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && **tt.dest != *tt.want) { //nolint:lll + if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && **tt.dest != *tt.want) { t.Errorf("copyStringPtr() got = %v, want %v", *tt.dest, tt.want) } }) @@ -201,7 +201,7 @@ func TestCopyTimePtr(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() copyTimePtr(tt.src, tt.dest) - if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && !(*tt.dest).Equal(*tt.want)) { //nolint:lll + if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && !(*tt.dest).Equal(*tt.want)) { t.Errorf("copyTimePtr() got = %v, want %v", *tt.dest, tt.want) } }) @@ -283,7 +283,7 @@ func TestCopyRepoAssociationPtr(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() copyRepoAssociationPtr(tt.src, tt.dest) - if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && !reflect.DeepEqual(**tt.dest, *tt.want)) { //nolint:lll + if (tt.want == nil && *tt.dest != nil) || (tt.want != nil && *tt.dest == nil) || (tt.want != nil && *tt.dest != nil && !reflect.DeepEqual(**tt.dest, *tt.want)) { t.Errorf("copyRepoAssociationPtr() got = %v, want %v", *tt.dest, tt.want) } }) diff --git a/clients/githubrepo/roundtripper/tokens/accessor_test.go b/clients/githubrepo/roundtripper/tokens/accessor_test.go index 1736eb5a4d7..129b959cbb4 100644 --- a/clients/githubrepo/roundtripper/tokens/accessor_test.go +++ b/clients/githubrepo/roundtripper/tokens/accessor_test.go @@ -85,15 +85,9 @@ func testServer(t *testing.T) { serverURL := strings.TrimPrefix(server.URL, "http://") t.Setenv("GITHUB_AUTH_SERVER", serverURL) t.Cleanup(server.Close) - myRPCService := &MyRPCService{} - rpc.Register(myRPCService) //nolint:errcheck rpc.HandleHTTP() got := MakeTokenAccessor() if got == nil { t.Errorf("MakeTokenAccessor() = nil, want not nil") } } - -type MyRPCService struct { - // Define your RPC service methods here -} diff --git a/clients/githubrepo/webhook_test.go b/clients/githubrepo/webhook_test.go index 15829c77281..97eae7ab03d 100644 --- a/clients/githubrepo/webhook_test.go +++ b/clients/githubrepo/webhook_test.go @@ -33,7 +33,6 @@ type stubTripper struct { func (s stubTripper) RoundTrip(_ *http.Request) (*http.Response, error) { f, err := os.Open(s.responsePath) if err != nil { - //nolint:wrapcheck return nil, err } return &http.Response{ diff --git a/clients/gitlabrepo/branches_test.go b/clients/gitlabrepo/branches_test.go index 9f5f2eb5aea..10269e1814c 100644 --- a/clients/gitlabrepo/branches_test.go +++ b/clients/gitlabrepo/branches_test.go @@ -110,11 +110,12 @@ func TestGetBranches(t *testing.T) { handler.once.Do(func() {}) - //nolint:errcheck - br, _ := handler.getBranch(tt.branchName) + br, err := handler.getBranch(tt.branchName) + if err != nil { + t.Fatalf("unexpected err: %v", err) + } - //nolint:unconvert - if string(*br.Name) != tt.expectedBranchName { + if *br.Name != tt.expectedBranchName { t.Errorf("Branch Name (%s) didn't match expected value (%s)", *br.Name, tt.expectedBranchName) } diff --git a/clients/gitlabrepo/issues_test.go b/clients/gitlabrepo/issues_test.go index f61ee63fb0d..32a5a2d41cd 100644 --- a/clients/gitlabrepo/issues_test.go +++ b/clients/gitlabrepo/issues_test.go @@ -40,7 +40,6 @@ func (s suffixStubTripper) RoundTrip(r *http.Request) (*http.Response, error) { suffix := pathParts[len(pathParts)-1] f, err := os.Open(s.responsePaths[suffix]) if err != nil { - //nolint:wrapcheck return nil, err } return &http.Response{ diff --git a/clients/gitlabrepo/webhook_test.go b/clients/gitlabrepo/webhook_test.go index bc69cea2c5b..01093de39bf 100644 --- a/clients/gitlabrepo/webhook_test.go +++ b/clients/gitlabrepo/webhook_test.go @@ -32,7 +32,6 @@ type stubTripper struct { func (s stubTripper) RoundTrip(_ *http.Request) (*http.Response, error) { f, err := os.Open(s.responsePath) if err != nil { - //nolint:wrapcheck return nil, err } return &http.Response{ diff --git a/cmd/internal/nuget/client_test.go b/cmd/internal/nuget/client_test.go index de369fdd3f9..350386d42f6 100644 --- a/cmd/internal/nuget/client_test.go +++ b/cmd/internal/nuget/client_test.go @@ -390,7 +390,6 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { resultPackageRegistrationPages: []resultPackagePage{}, resultPackageSpec: "", }, - //nolint:lll want: "internal error: failed to parse nuget package registration index json: invalid character 'e' in literal true (expecting 'r')", wantErr: true, }, @@ -443,7 +442,6 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { }, resultPackageSpec: "", }, - //nolint:lll want: "internal error: failed to parse nuget package registration page: invalid character 'e' in literal true (expecting 'r')", wantErr: true, }, @@ -514,7 +512,6 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { resultPackageSpec: "", version: "", }, - //nolint:lll want: "internal error: failed to parse nuget package registration index json: failed to unmarshal json: json: cannot unmarshal number into Go struct field Alias.listed of type bool", wantErr: true, }, @@ -580,7 +577,6 @@ func nugetIndexOrPageTestResults(url string, test *nugetTest) (*http.Response, e urlResponseIndex := slices.IndexFunc(test.args.resultPackageRegistrationPages, func(page resultPackagePage) bool { return page.url == url }) if urlResponseIndex == -1 { - //nolint:goerr113 return nil, errors.New("error") } page := test.args.resultPackageRegistrationPages[urlResponseIndex] @@ -597,13 +593,11 @@ func nugetPackageIndexAndSpecResponse(t *testing.T, url string, test *nugetTest) } t.Errorf("fetchGitRepositoryFromNuget() version = %v, expected version = %v", url, test.args.version) } - //nolint:goerr113 return nil, errors.New("error") } func testResult(wantErr bool, responseFileName string) (*http.Response, error) { if wantErr && responseFileName == "" { - //nolint:goerr113 return nil, errors.New("error") } if wantErr && responseFileName == "text" { diff --git a/cmd/internal/scdiff/app/compare_test.go b/cmd/internal/scdiff/app/compare_test.go index 8b8da9dfef5..f4bfc5b3816 100644 --- a/cmd/internal/scdiff/app/compare_test.go +++ b/cmd/internal/scdiff/app/compare_test.go @@ -21,7 +21,6 @@ import ( "testing" ) -//nolint:lll // results are long func Test_compare(t *testing.T) { t.Parallel() //nolint:govet // struct alignment @@ -97,7 +96,6 @@ func (a alwaysErrorReader) Read(b []byte) (n int, err error) { return 0, io.ErrClosedPipe } -//nolint:lll // results are long func Test_compare_reader_err(t *testing.T) { t.Parallel() //nolint:govet // struct alignment diff --git a/cmd/internal/scdiff/app/generate_test.go b/cmd/internal/scdiff/app/generate_test.go index fd7f142e10a..f8dbb79fc80 100644 --- a/cmd/internal/scdiff/app/generate_test.go +++ b/cmd/internal/scdiff/app/generate_test.go @@ -31,7 +31,6 @@ type resultCounter struct { lines int } -//nolint:wrapcheck func (rc *resultCounter) Write(p []byte) (n int, err error) { rc.lines += bytes.Count(p, []byte("\n")) return rc.b.Write(p) diff --git a/cmd/package_managers_test.go b/cmd/package_managers_test.go index 8b70eac8fc7..a8ba8ec1e97 100644 --- a/cmd/package_managers_test.go +++ b/cmd/package_managers_test.go @@ -141,7 +141,6 @@ func Test_fetchGitRepositoryFromNPM(t *testing.T) { p.EXPECT().Get(gomock.Any(), tt.args.packageName). DoAndReturn(func(url, packageName string) (*http.Response, error) { if tt.wantErr && tt.args.result == "" { - //nolint:goerr113 return nil, errors.New("error") } @@ -316,7 +315,6 @@ func Test_fetchGitRepositoryFromPYPI(t *testing.T) { name: "fetchGitRepositoryFromPYPI", args: args{ packageName: "some-package", - //nolint:lll result: ` { "info": { @@ -450,7 +448,6 @@ func Test_fetchGitRepositoryFromPYPI(t *testing.T) { p.EXPECT().Get(gomock.Any(), tt.args.packageName). DoAndReturn(func(url, packageName string) (*http.Response, error) { if tt.wantErr && tt.args.result == "" { - //nolint:goerr113 return nil, errors.New("error") } @@ -487,7 +484,6 @@ func Test_fetchGitRepositoryFromRubyGems(t *testing.T) { name: "fetchGitRepositoryFromPYPI", args: args{ packageName: "npm-package", - //nolint:lll result: ` { "name": "color", @@ -609,7 +605,6 @@ func Test_fetchGitRepositoryFromRubyGems(t *testing.T) { name: "empty project url", args: args{ packageName: "npm-package", - //nolint:lll result: ` { "name": "color", @@ -717,7 +712,6 @@ func Test_fetchGitRepositoryFromRubyGems(t *testing.T) { p.EXPECT().Get(gomock.Any(), tt.args.packageName). DoAndReturn(func(url, packageName string) (*http.Response, error) { if tt.wantErr && tt.args.result == "" { - //nolint:goerr113 return nil, errors.New("error") } @@ -778,7 +772,6 @@ func Test_fetchGitRepositoryFromNuget(t *testing.T) { n.EXPECT().GitRepositoryByPackageName(tt.args.packageName). DoAndReturn(func(packageName string) (string, error) { if tt.wantErr && tt.args.result == "" { - //nolint:goerr113 return "", errors.New("error") } diff --git a/cron/config/config_test.go b/cron/config/config_test.go index c1356a3a754..6fe09b22a7d 100644 --- a/cron/config/config_test.go +++ b/cron/config/config_test.go @@ -70,7 +70,6 @@ func getByteValueFromFile(filename string) ([]byte, error) { if filename == "" { return nil, nil } - //nolint:wrapcheck return os.ReadFile(filename) } diff --git a/cron/internal/pubsub/publisher_test.go b/cron/internal/pubsub/publisher_test.go index 0860e77c71f..524e95c7503 100644 --- a/cron/internal/pubsub/publisher_test.go +++ b/cron/internal/pubsub/publisher_test.go @@ -33,7 +33,6 @@ func (topic *mockSucceedTopic) Send(ctx context.Context, msg *pubsub.Message) er type mockFailTopic struct{} func (topic *mockFailTopic) Send(ctx context.Context, msg *pubsub.Message) error { - //nolint:goerr113 return fmt.Errorf("mockFailTopic failed to send") } diff --git a/cron/internal/pubsub/subscriber_gocloud_test.go b/cron/internal/pubsub/subscriber_gocloud_test.go index 791b8d77874..621349ace35 100644 --- a/cron/internal/pubsub/subscriber_gocloud_test.go +++ b/cron/internal/pubsub/subscriber_gocloud_test.go @@ -65,8 +65,7 @@ func TestSubscriber(t *testing.T) { { name: "ReceiveFails", hasErrOnReceive: true, - //nolint:goerr113 - errOnReceive: errors.New("mock Receive failure"), + errOnReceive: errors.New("mock Receive failure"), }, { name: "ShutdownFails", @@ -78,8 +77,7 @@ func TestSubscriber(t *testing.T) { }, }, hasErrOnShutdown: true, - //nolint:goerr113 - errOnShutdown: errors.New("mock Shutdown close"), + errOnShutdown: errors.New("mock Shutdown close"), }, } for _, testcase := range testcases { diff --git a/e2e/attestor_policy_test.go b/e2e/attestor_policy_test.go index 9fe2c7b7ed2..218e5998dae 100644 --- a/e2e/attestor_policy_test.go +++ b/e2e/attestor_policy_test.go @@ -247,6 +247,6 @@ func getScorecardResult(repoURL string) (pkg.ScorecardResult, error) { if err != nil { return pkg.ScorecardResult{}, fmt.Errorf("couldn't set up clients: %w", err) } - //nolint:wrapcheck,lll + return pkg.RunScorecard(ctx, repo, clients.HeadSHA, 0, enabledChecks, repoClient, ossFuzzRepoClient, ciiClient, vulnsClient) } diff --git a/errors/internal_test.go b/errors/internal_test.go index c8a077b7f1c..b1ea3b74a69 100644 --- a/errors/internal_test.go +++ b/errors/internal_test.go @@ -32,10 +32,10 @@ func TestCreateInternal(t *testing.T) { }{ name: "non-nil error and non-empty message", args: args{ - e: errors.New("test error"), //nolint:goerr113 + e: errors.New("test error"), msg: "test message", }, - want: fmt.Errorf("test error: test message"), //nolint:goerr113 + want: fmt.Errorf("test error: test message"), } t.Run(test.name, func(t *testing.T) { diff --git a/errors/public_test.go b/errors/public_test.go index 70339ea0123..16a8c0b56c1 100644 --- a/errors/public_test.go +++ b/errors/public_test.go @@ -92,7 +92,7 @@ func TestGetName(t *testing.T) { { name: "unknown error", args: args{ - err: errors.New("unknown error"), //nolint:goerr113 + err: errors.New("unknown error"), }, want: "ErrUnknown", }, diff --git a/options/flags_test.go b/options/flags_test.go index 4dbd6f5c6b4..21d88404255 100644 --- a/options/flags_test.go +++ b/options/flags_test.go @@ -175,7 +175,7 @@ func TestOptions_AddFlags_Format(t *testing.T) { cmd := &cobra.Command{} tt.opts.AddFlags(cmd) if !cmp.Equal(cmd.Flag(FlagFormat).Value.String(), strings.Join(tt.expected, ", ")) { - t.Errorf("expected FlagFormat to be %q, but got %q", strings.Join(tt.expected, ", "), cmd.Flag(FlagFormat).Value.String()) //nolint:lll + t.Errorf("expected FlagFormat to be %q, but got %q", strings.Join(tt.expected, ", "), cmd.Flag(FlagFormat).Value.String()) } }) } diff --git a/pkg/json_raw_results_test.go b/pkg/json_raw_results_test.go index 82adcc8b116..7b489c324d0 100644 --- a/pkg/json_raw_results_test.go +++ b/pkg/json_raw_results_test.go @@ -583,7 +583,7 @@ func TestJsonScorecardRawResult_AddOssfBestPracticesRawResults(t *testing.T) { t.Errorf("addOssfBestPracticesRawResults() error = %v, wantError %v", err, test.wantError) } if r.Results.OssfBestPractices.Badge != test.input.Badge.String() { - t.Errorf("addOssfBestPracticesRawResults() badge = %v, want %v", r.Results.OssfBestPractices.Badge, test.input.Badge.String()) //nolint:lll + t.Errorf("addOssfBestPracticesRawResults() badge = %v, want %v", r.Results.OssfBestPractices.Badge, test.input.Badge.String()) } }) } @@ -650,7 +650,7 @@ func TestJsonScorecardRawResult_AddCodeReviewRawResults(t *testing.T) { t.Errorf("addCodeReviewRawResults() error = %v, wantError %v", err, test.wantError) } if len(r.Results.DefaultBranchChangesets) != len(test.input.DefaultBranchChangesets) { - t.Errorf("addCodeReviewRawResults() changesets length = %v, want %v", len(r.Results.DefaultBranchChangesets), len(test.input.DefaultBranchChangesets)) //nolint:lll + t.Errorf("addCodeReviewRawResults() changesets length = %v, want %v", len(r.Results.DefaultBranchChangesets), len(test.input.DefaultBranchChangesets)) } }) } @@ -724,7 +724,7 @@ func TestAddCodeReviewRawResults(t *testing.T) { } if !reflect.DeepEqual(r.Results.DefaultBranchChangesets, expected) { - t.Errorf("addCodeReviewRawResults did not produce the expected output. Got: %v, Expected: %v", r.Results.DefaultBranchChangesets, expected) //nolint:lll + t.Errorf("addCodeReviewRawResults did not produce the expected output. Got: %v, Expected: %v", r.Results.DefaultBranchChangesets, expected) } } @@ -820,12 +820,12 @@ func TestAddBinaryArtifactRawResults(t *testing.T) { } if len(r.Results.Binaries) != len(expected) { - t.Errorf("addBinaryArtifactRawResults did not add the correct number of files. Expected %d, got %d", len(expected), len(r.Results.Binaries)) //nolint:lll + t.Errorf("addBinaryArtifactRawResults did not add the correct number of files. Expected %d, got %d", len(expected), len(r.Results.Binaries)) } for i, file := range r.Results.Binaries { if file.Path != expected[i].Path { - t.Errorf("addBinaryArtifactRawResults did not add the correct file. Expected %s, got %s", expected[i].Path, file.Path) //nolint:lll + t.Errorf("addBinaryArtifactRawResults did not add the correct file. Expected %s, got %s", expected[i].Path, file.Path) } } } @@ -892,25 +892,25 @@ func TestAddSecurityPolicyRawResults(t *testing.T) { } if len(r.Results.SecurityPolicies) != len(expected) { - t.Errorf("addSecurityPolicyRawResults did not add the correct number of policies. Expected %d, got %d", len(expected), len(r.Results.SecurityPolicies)) //nolint:lll + t.Errorf("addSecurityPolicyRawResults did not add the correct number of policies. Expected %d, got %d", len(expected), len(r.Results.SecurityPolicies)) } for i, policy := range r.Results.SecurityPolicies { if policy.Path != expected[i].Path { - t.Errorf("addSecurityPolicyRawResults did not add the correct policy. Expected %s, got %s", expected[i].Path, policy.Path) //nolint:lll + t.Errorf("addSecurityPolicyRawResults did not add the correct policy. Expected %s, got %s", expected[i].Path, policy.Path) } if policy.ContentLength != expected[i].ContentLength { - t.Errorf("addSecurityPolicyRawResults did not add the correct content length. Expected %d, got %d", expected[i].ContentLength, policy.ContentLength) //nolint:lll + t.Errorf("addSecurityPolicyRawResults did not add the correct content length. Expected %d, got %d", expected[i].ContentLength, policy.ContentLength) } if len(policy.Hits) != len(expected[i].Hits) { - t.Errorf("addSecurityPolicyRawResults did not add the correct number of hits. Expected %d, got %d", len(expected[i].Hits), len(policy.Hits)) //nolint:lll + t.Errorf("addSecurityPolicyRawResults did not add the correct number of hits. Expected %d, got %d", len(expected[i].Hits), len(policy.Hits)) } for j, hit := range policy.Hits { if hit.Type != expected[i].Hits[j].Type { - t.Errorf("addSecurityPolicyRawResults did not add the correct hit type. Expected %s, got %s", expected[i].Hits[j].Type, hit.Type) //nolint:lll + t.Errorf("addSecurityPolicyRawResults did not add the correct hit type. Expected %s, got %s", expected[i].Hits[j].Type, hit.Type) } } } @@ -944,12 +944,12 @@ func TestAddVulnerabilitiesRawResults(t *testing.T) { } if len(r.Results.DatabaseVulnerabilities) != len(expected) { - t.Errorf("addVulnerbilitiesRawResults did not add the correct number of vulnerabilities. Expected %d, got %d", len(expected), len(r.Results.DatabaseVulnerabilities)) //nolint:lll + t.Errorf("addVulnerbilitiesRawResults did not add the correct number of vulnerabilities. Expected %d, got %d", len(expected), len(r.Results.DatabaseVulnerabilities)) } for i, vuln := range r.Results.DatabaseVulnerabilities { if vuln.ID != expected[i].ID { - t.Errorf("addVulnerbilitiesRawResults did not add the correct vulnerability. Expected %s, got %s", expected[i].ID, vuln.ID) //nolint:lll + t.Errorf("addVulnerbilitiesRawResults did not add the correct vulnerability. Expected %s, got %s", expected[i].ID, vuln.ID) } } } @@ -1016,24 +1016,24 @@ func TestAddFuzzingRawResults(t *testing.T) { } if len(r.Results.Fuzzers) != len(expectedFuzzers) { - t.Errorf("addFuzzingRawResults did not add the correct number of fuzzers. Expected %d, got %d", len(expectedFuzzers), len(r.Results.Fuzzers)) //nolint:lll + t.Errorf("addFuzzingRawResults did not add the correct number of fuzzers. Expected %d, got %d", len(expectedFuzzers), len(r.Results.Fuzzers)) } for i, fuzzer := range r.Results.Fuzzers { if fuzzer.Name != expectedFuzzers[i].Name { - t.Errorf("addFuzzingRawResults did not add the correct fuzzer name. Expected %s, got %s", expectedFuzzers[i].Name, fuzzer.Name) //nolint:lll + t.Errorf("addFuzzingRawResults did not add the correct fuzzer name. Expected %s, got %s", expectedFuzzers[i].Name, fuzzer.Name) } if *fuzzer.URL != *expectedFuzzers[i].URL { - t.Errorf("addFuzzingRawResults did not add the correct fuzzer URL. Expected %s, got %s", *expectedFuzzers[i].URL, *fuzzer.URL) //nolint:lll + t.Errorf("addFuzzingRawResults did not add the correct fuzzer URL. Expected %s, got %s", *expectedFuzzers[i].URL, *fuzzer.URL) } if *fuzzer.Desc != *expectedFuzzers[i].Desc { - t.Errorf("addFuzzingRawResults did not add the correct fuzzer description. Expected %s, got %s", *expectedFuzzers[i].Desc, *fuzzer.Desc) //nolint:lll + t.Errorf("addFuzzingRawResults did not add the correct fuzzer description. Expected %s, got %s", *expectedFuzzers[i].Desc, *fuzzer.Desc) } if len(fuzzer.Files) != len(expectedFuzzers[i].Files) { - t.Errorf("addFuzzingRawResults did not add the correct number of files for fuzzer %s. Expected %d, got %d", fuzzer.Name, len(expectedFuzzers[i].Files), len(fuzzer.Files)) //nolint:lll + t.Errorf("addFuzzingRawResults did not add the correct number of files for fuzzer %s. Expected %d, got %d", fuzzer.Name, len(expectedFuzzers[i].Files), len(fuzzer.Files)) } for j, file := range fuzzer.Files { if file.Path != expectedFuzzers[i].Files[j].Path { - t.Errorf("addFuzzingRawResults did not add the correct file path for fuzzer %s. Expected %s, got %s", fuzzer.Name, expectedFuzzers[i].Files[j].Path, file.Path) //nolint:lll + t.Errorf("addFuzzingRawResults did not add the correct file path for fuzzer %s. Expected %s, got %s", fuzzer.Name, expectedFuzzers[i].Files[j].Path, file.Path) } } } @@ -1137,7 +1137,7 @@ func TestJsonScorecardRawResult(t *testing.T) { {ID: "CVE-2021-5678"}, } if cmp.Diff(r.Results.DatabaseVulnerabilities, expectedVulnerabilities) != "" { - t.Errorf("addVulnerbilitiesRawResults did not produce the expected results %v", cmp.Diff(r.Results.DatabaseVulnerabilities, expectedVulnerabilities)) //nolint:lll + t.Errorf("addVulnerbilitiesRawResults did not produce the expected results %v", cmp.Diff(r.Results.DatabaseVulnerabilities, expectedVulnerabilities)) } // test addBinaryArtifactRawResults @@ -1173,7 +1173,7 @@ func TestJsonScorecardRawResult(t *testing.T) { }, } if cmp.Diff(expectedSecurityPolicies, r.Results.SecurityPolicies) != "" { - t.Errorf("addSecurityPolicyRawResults did not produce the expected results %v", cmp.Diff(expectedSecurityPolicies, r.Results.SecurityPolicies)) //nolint:lll + t.Errorf("addSecurityPolicyRawResults did not produce the expected results %v", cmp.Diff(expectedSecurityPolicies, r.Results.SecurityPolicies)) } // test addFuzzingRawResults @@ -1202,7 +1202,7 @@ func TestJsonScorecardRawResult(t *testing.T) { }, } if cmp.Diff(expectedFuzzers, r.Results.Fuzzers, cmpopts.IgnoreFields(jsonTool{}, "URL", "Desc")) != "" { - t.Errorf("addFuzzingRawResults did not produce the expected results %v", cmp.Diff(expectedFuzzers, r.Results.Fuzzers)) //nolint:lll + t.Errorf("addFuzzingRawResults did not produce the expected results %v", cmp.Diff(expectedFuzzers, r.Results.Fuzzers)) } // test addBranchProtectionRawResults @@ -1224,7 +1224,6 @@ func intPtr(i int32) *int32 { return &i } -//nolint:lll func TestScorecardResult_AsRawJSON(t *testing.T) { type fields struct { Repo RepoInfo @@ -1249,7 +1248,7 @@ func TestScorecardResult_AsRawJSON(t *testing.T) { }, }, wantWriter: `{"date":"0001-01-01","repo":{"name":"bar","commit":"1234567890123456789012345678901234567890"},"scorecard":{"version":"","commit":""},"metadata":null,"results":{"workflows":[],"permissions":{},"licenses":[],"issues":null,"openssfBestPracticesBadge":{"badge":"Unknown"},"databaseVulnerabilities":[],"binaries":[],"securityPolicies":[],"dependencyUpdateTools":[],"branchProtections":{"branches":[],"codeownersFiles":null},"Contributors":{"users":null},"defaultBranchChangesets":[],"archived":{"status":false},"createdAt":{"timestamp":"0001-01-01T00:00:00Z"},"fuzzers":[],"releases":[],"packages":[],"dependencyPinning":{"dependencies":null}}} -`, //nolint:lll +`, }, } for _, tt := range tests { diff --git a/pkg/json_test.go b/pkg/json_test.go index 7b39de2b251..7391cfb1efd 100644 --- a/pkg/json_test.go +++ b/pkg/json_test.go @@ -495,7 +495,7 @@ func TestJSONOutput(t *testing.T) { func TestExperimentalFromJSON2_time(t *testing.T) { t.Parallel() - //nolint:lll,govet // result strings are long + //nolint:govet tests := []struct { name string result string diff --git a/pkg/scorecard_e2e_test.go b/pkg/scorecard_e2e_test.go index 4e641e56e1c..921a205daf5 100644 --- a/pkg/scorecard_e2e_test.go +++ b/pkg/scorecard_e2e_test.go @@ -52,7 +52,7 @@ func countDetails(c []checker.CheckDetail) (debug, info, warn int) { return debug, info, warn } -//nolint:lll,gocritic // comparison was failing with pointer types +//nolint:gocritic // comparison was failing with pointer types func compareScorecardResults(a, b ScorecardResult) bool { if a.Repo != b.Repo { fmt.Fprintf(GinkgoWriter, "Unequal repo details in results: %v vs %v\n", a.Repo, b.Repo) diff --git a/probes/hasOSVVulnerabilities/impl_test.go b/probes/hasOSVVulnerabilities/impl_test.go index 46d64ecbe51..75a88a0be48 100644 --- a/probes/hasOSVVulnerabilities/impl_test.go +++ b/probes/hasOSVVulnerabilities/impl_test.go @@ -88,11 +88,9 @@ func Test_Run(t *testing.T) { Probe: "hasOSVVulnerabilities", Message: "Project is vulnerable to: foo", Remediation: &probe.Remediation{ - //nolint:lll Text: `Fix the foo by following information from https://osv.dev/foo. If the vulnerability is in a dependency, update the dependency to a non-vulnerable version. If no update is available, consider whether to remove the dependency. If you believe the vulnerability does not affect your project, the vulnerability can be ignored. To ignore, create an osv-scanner.toml file next to the dependency manifest (e.g. package-lock.json) and specify the ID to ignore and reason. Details on the structure of osv-scanner.toml can be found on OSV-Scanner repository.`, - //nolint:lll Markdown: `Fix the foo by following information from [OSV](https://osv.dev/foo). If the vulnerability is in a dependency, update the dependency to a non-vulnerable version. If no update is available, consider whether to remove the dependency. If you believe the vulnerability does not affect your project, the vulnerability can be ignored. To ignore, create an osv-scanner.toml ([example](https://github.com/google/osv.dev/blob/eb99b02ec8895fe5b87d1e76675ddad79a15f817/vulnfeeds/osv-scanner.toml)) file next to the dependency manifest (e.g. package-lock.json) and specify the ID to ignore and reason. Details on the structure of osv-scanner.toml can be found on [OSV-Scanner repository](https://github.com/google/osv-scanner#ignore-vulnerabilities-by-id).`, diff --git a/remediation/remediations_test.go b/remediation/remediations_test.go index dce119881d5..3ea529aad58 100644 --- a/remediation/remediations_test.go +++ b/remediation/remediations_test.go @@ -66,7 +66,6 @@ func (s stubDigester) Digest(name string) (string, error) { } hash, ok := m[name] if !ok { - //nolint:goerr113 return "", fmt.Errorf("no hash for image: %q", name) } return fmt.Sprintf("sha256:%s", hash), nil @@ -75,7 +74,7 @@ func (s stubDigester) Digest(name string) (string, error) { func TestCreateDockerfilePinningRemediation(t *testing.T) { t.Parallel() - //nolint:govet,lll + //nolint:govet tests := []struct { name string dep checker.Dependency From d882fc73e120c04b2a2a6b1ec6fb5eed74f72b92 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Sun, 3 Dec 2023 18:25:03 -0800 Subject: [PATCH 30/51] :seedling: re-enable paralleltest linter (#3705) Signed-off-by: Spencer Schrock --- .golangci.yml | 1 - attestor/command/cli_test.go | 62 +++++++++---------- checker/detail_logger_impl_test.go | 6 ++ checker/raw_result_test.go | 1 + checks/evaluation/pinned_dependencies_test.go | 3 + checks/evaluation/signed_releases_test.go | 3 + checks/raw/binary_artifact_test.go | 1 + checks/raw/contributors_test.go | 1 + checks/raw/license_test.go | 1 - checks/raw/maintained_test.go | 1 + checks/raw/shell_download_validate_test.go | 12 ++++ clients/git/client_test.go | 8 ++- clients/githubrepo/checkruns_test.go | 1 + clients/githubrepo/graphql_test.go | 1 + .../internal/fnmatch/fnmatch_test.go | 1 + .../roundtripper/tokens/accessor_test.go | 2 +- .../roundtripper/tokens/round_robin_test.go | 3 +- .../roundtripper/tokens/rpc_test.go | 2 + clients/gitlabrepo/repo_test.go | 1 + clients/ossfuzz/client_test.go | 1 + .../scdiff/app/compare/compare_test.go | 3 + cmd/internal/scdiff/app/format/format_test.go | 1 + cmd/internal/scdiff/app/runner/runner_test.go | 2 + dependencydiff/dependencydiff_test.go | 8 +++ e2e/e2e_suite_test.go | 1 + errors/internal_test.go | 2 + pkg/json_raw_results_test.go | 11 ++++ pkg/pkg_suite_test.go | 1 + policy/policy_test.go | 1 + 29 files changed, 104 insertions(+), 38 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 350c4328101..6468694225f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -75,7 +75,6 @@ linters: - wrapcheck disable: - exhaustruct # initializing every struct makes tests longer without much benefit (spencerschrock) - - paralleltest # need to investigate rate limit issues before re-enabling? (#2527) - testpackage # tests don't need their own package (spencerschrock) presets: - bugs diff --git a/attestor/command/cli_test.go b/attestor/command/cli_test.go index ca0a7d499a1..0ba516271cb 100644 --- a/attestor/command/cli_test.go +++ b/attestor/command/cli_test.go @@ -20,43 +20,41 @@ import ( ) func Test_addSignFlags(t *testing.T) { + t.Parallel() type args struct { cmd *cobra.Command } - testName := "Test addSignFlags" testArgs := args{ cmd: &cobra.Command{}, } - t.Run(testName, func(t *testing.T) { - addSignFlags(testArgs.cmd) - // persistent flags of Image being set has to be tested in the integration test - if testArgs.cmd.PersistentFlags().Lookup("image") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'image'") - } - if testArgs.cmd.PersistentFlags().Lookup("attestation-project") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'attestation-project'") - } - if testArgs.cmd.PersistentFlags().Lookup("overwrite") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'overwrite'") - } - if testArgs.cmd.PersistentFlags().Lookup("kms-key-name") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'kms-key-name'") - } - if testArgs.cmd.PersistentFlags().Lookup("kms-digest-alg") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'kms-digest-alg'") - } - if testArgs.cmd.PersistentFlags().Lookup("pgp-private-key") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'pgp-private-key'") - } - if testArgs.cmd.PersistentFlags().Lookup("pgp-passphrase") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'pgp-passphrase'") - } - if testArgs.cmd.PersistentFlags().Lookup("pkix-private-key") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'pkix-private-key'") - } - if testArgs.cmd.PersistentFlags().Lookup("pkix-alg") == nil { - t.Errorf("addSignFlags() did not add persistent flag 'pkix-alg'") - } - }) + addSignFlags(testArgs.cmd) + // persistent flags of Image being set has to be tested in the integration test + if testArgs.cmd.PersistentFlags().Lookup("image") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'image'") + } + if testArgs.cmd.PersistentFlags().Lookup("attestation-project") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'attestation-project'") + } + if testArgs.cmd.PersistentFlags().Lookup("overwrite") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'overwrite'") + } + if testArgs.cmd.PersistentFlags().Lookup("kms-key-name") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'kms-key-name'") + } + if testArgs.cmd.PersistentFlags().Lookup("kms-digest-alg") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'kms-digest-alg'") + } + if testArgs.cmd.PersistentFlags().Lookup("pgp-private-key") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'pgp-private-key'") + } + if testArgs.cmd.PersistentFlags().Lookup("pgp-passphrase") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'pgp-passphrase'") + } + if testArgs.cmd.PersistentFlags().Lookup("pkix-private-key") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'pkix-private-key'") + } + if testArgs.cmd.PersistentFlags().Lookup("pkix-alg") == nil { + t.Errorf("addSignFlags() did not add persistent flag 'pkix-alg'") + } } diff --git a/checker/detail_logger_impl_test.go b/checker/detail_logger_impl_test.go index c1cebcb8a61..e81901d3eb9 100644 --- a/checker/detail_logger_impl_test.go +++ b/checker/detail_logger_impl_test.go @@ -18,6 +18,7 @@ import ( ) func Test_logger_Info(t *testing.T) { + t.Parallel() l := &logger{ logs: []CheckDetail{}, } @@ -28,6 +29,7 @@ func Test_logger_Info(t *testing.T) { } func Test_logger_Warn(t *testing.T) { + t.Parallel() l := &logger{ logs: []CheckDetail{}, } @@ -38,6 +40,7 @@ func Test_logger_Warn(t *testing.T) { } func Test_logger_Flush(t *testing.T) { + t.Parallel() l := &logger{ logs: []CheckDetail{}, } @@ -52,6 +55,7 @@ func Test_logger_Flush(t *testing.T) { } func Test_logger_Logs(t *testing.T) { + t.Parallel() l := &logger{ logs: []CheckDetail{}, } @@ -62,6 +66,7 @@ func Test_logger_Logs(t *testing.T) { } func Test_logger_Debug(t *testing.T) { + t.Parallel() l := &logger{ logs: []CheckDetail{}, } @@ -72,6 +77,7 @@ func Test_logger_Debug(t *testing.T) { } func TestNewLogger(t *testing.T) { + t.Parallel() l := NewLogger() if l == nil { t.Errorf("expected non-nil logger, got nil") diff --git a/checker/raw_result_test.go b/checker/raw_result_test.go index 7c519e73cb7..4a04d7d0abc 100644 --- a/checker/raw_result_test.go +++ b/checker/raw_result_test.go @@ -20,6 +20,7 @@ import ( ) func TestFile_Location(t *testing.T) { + t.Parallel() file := File{ Type: finding.FileTypeSource, Path: "bar.go", diff --git a/checks/evaluation/pinned_dependencies_test.go b/checks/evaluation/pinned_dependencies_test.go index c90c07e7246..41b6d6c6850 100644 --- a/checks/evaluation/pinned_dependencies_test.go +++ b/checks/evaluation/pinned_dependencies_test.go @@ -988,6 +988,7 @@ func Test_addWorkflowPinnedResult(t *testing.T) { } func TestGenerateText(t *testing.T) { + t.Parallel() tests := []struct { name string dependency *checker.Dependency @@ -1016,7 +1017,9 @@ func TestGenerateText(t *testing.T) { } for _, tc := range tests { + tc := tc t.Run(tc.name, func(t *testing.T) { + t.Parallel() result := generateTextUnpinned(tc.dependency) if !cmp.Equal(tc.expectedText, result) { t.Errorf("generateText mismatch (-want +got):\n%s", cmp.Diff(tc.expectedText, result)) diff --git a/checks/evaluation/signed_releases_test.go b/checks/evaluation/signed_releases_test.go index 35cf5cff0ff..53a8ee362e2 100644 --- a/checks/evaluation/signed_releases_test.go +++ b/checks/evaluation/signed_releases_test.go @@ -26,6 +26,7 @@ import ( ) func TestSignedReleases(t *testing.T) { + t.Parallel() tests := []struct { name string releases []clients.Release @@ -93,7 +94,9 @@ func TestSignedReleases(t *testing.T) { } for _, tc := range tests { + tc := tc t.Run(tc.name, func(t *testing.T) { + t.Parallel() dl := &scut.TestDetailLogger{} data := &checker.SignedReleasesData{Releases: tc.releases} actualResult := SignedReleases("Signed-Releases", dl, data) diff --git a/checks/raw/binary_artifact_test.go b/checks/raw/binary_artifact_test.go index ae9970bc500..ace73e34f69 100644 --- a/checks/raw/binary_artifact_test.go +++ b/checks/raw/binary_artifact_test.go @@ -258,6 +258,7 @@ func TestBinaryArtifacts(t *testing.T) { } func TestBinaryArtifacts_workflow_runs_unsupported(t *testing.T) { + t.Parallel() ctrl := gomock.NewController(t) mockRepoClient := mockrepo.NewMockRepoClient(ctrl) const jarFile = "gradle-wrapper.jar" diff --git a/checks/raw/contributors_test.go b/checks/raw/contributors_test.go index 7b2da17c915..f7a2c51dc1a 100644 --- a/checks/raw/contributors_test.go +++ b/checks/raw/contributors_test.go @@ -105,6 +105,7 @@ func TestOrgContains(t *testing.T) { } func TestContributors(t *testing.T) { + t.Parallel() ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/checks/raw/license_test.go b/checks/raw/license_test.go index ce5a603154e..bc54e26c98c 100644 --- a/checks/raw/license_test.go +++ b/checks/raw/license_test.go @@ -646,7 +646,6 @@ func TestLicenseFileCheck(t *testing.T) { }, } - //nolint:paralleltest for _, tt := range tests { tt := tt // Re-initializing variable so it is not changed while executing the closure below for _, ext := range tt.extensions { diff --git a/checks/raw/maintained_test.go b/checks/raw/maintained_test.go index 2117175653a..5dc5db825ec 100644 --- a/checks/raw/maintained_test.go +++ b/checks/raw/maintained_test.go @@ -26,6 +26,7 @@ import ( mockrepo "github.com/ossf/scorecard/v4/clients/mockclients" ) +//nolint:paralleltest // need to break into separate tests func TestMaintained(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/checks/raw/shell_download_validate_test.go b/checks/raw/shell_download_validate_test.go index e7f615cac7a..44dfe065154 100644 --- a/checks/raw/shell_download_validate_test.go +++ b/checks/raw/shell_download_validate_test.go @@ -112,6 +112,7 @@ func TestValidateShellFile(t *testing.T) { } func Test_isDotNetUnpinnedDownload(t *testing.T) { + t.Parallel() type args struct { cmd []string } @@ -206,7 +207,9 @@ func Test_isDotNetUnpinnedDownload(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if got := isNugetUnpinnedDownload(tt.args.cmd); got != tt.want { t.Errorf("isNugetUnpinnedDownload() = %v, want %v", got, tt.want) } @@ -215,6 +218,7 @@ func Test_isDotNetUnpinnedDownload(t *testing.T) { } func Test_isGoUnpinnedDownload(t *testing.T) { + t.Parallel() type args struct { cmd []string } @@ -239,7 +243,9 @@ func Test_isGoUnpinnedDownload(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if got := isGoUnpinnedDownload(tt.args.cmd); got != tt.want { t.Errorf("isGoUnpinnedDownload() = %v, want %v", got, tt.want) } @@ -248,6 +254,7 @@ func Test_isGoUnpinnedDownload(t *testing.T) { } func Test_isNpmDownload(t *testing.T) { + t.Parallel() type args struct { cmd []string } @@ -272,7 +279,9 @@ func Test_isNpmDownload(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if got := isNpmDownload(tt.args.cmd); got != tt.want { t.Errorf("isNpmDownload() = %v, want %v", got, tt.want) } @@ -281,6 +290,7 @@ func Test_isNpmDownload(t *testing.T) { } func Test_isNpmUnpinnedDownload(t *testing.T) { + t.Parallel() type args struct { cmd []string } @@ -305,7 +315,9 @@ func Test_isNpmUnpinnedDownload(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if got := isNpmUnpinnedDownload(tt.args.cmd); got != tt.want { t.Errorf("isNpmUnpinnedDownload() = %v, want %v", got, tt.want) } diff --git a/clients/git/client_test.go b/clients/git/client_test.go index 483bad5977c..0bfa45a2357 100644 --- a/clients/git/client_test.go +++ b/clients/git/client_test.go @@ -77,8 +77,8 @@ func createTestRepo(t *testing.T) (path string) { return dir } -//nolint:paralleltest func TestInitRepo(t *testing.T) { + t.Parallel() tests := []struct { //nolint:govet name string uri string @@ -112,6 +112,7 @@ func TestInitRepo(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { + t.Parallel() uri := fmt.Sprintf(test.uri, repoPath) client := &Client{} @@ -124,6 +125,7 @@ func TestInitRepo(t *testing.T) { } func TestListCommits(t *testing.T) { + t.Parallel() repoPath := createTestRepo(t) client := &Client{} @@ -147,8 +149,8 @@ func TestListCommits(t *testing.T) { } } -//nolint:paralleltest func TestSearch(t *testing.T) { + t.Parallel() testCases := []struct { name string request clients.SearchRequest @@ -215,7 +217,9 @@ func TestSearch(t *testing.T) { } for _, tc := range testCases { + tc := tc t.Run(tc.name, func(t *testing.T) { + t.Parallel() client := &Client{} uri := fmt.Sprintf("file://%s", repoPath) if err := client.InitRepo(uri, "HEAD", 1); err != nil { diff --git a/clients/githubrepo/checkruns_test.go b/clients/githubrepo/checkruns_test.go index 2d12d68e464..ad5639260a1 100644 --- a/clients/githubrepo/checkruns_test.go +++ b/clients/githubrepo/checkruns_test.go @@ -22,6 +22,7 @@ import ( ) func Test_init_clearsErr(t *testing.T) { + t.Parallel() handler := &checkrunsHandler{errSetup: sce.ErrScorecardInternal} handler.init(context.Background(), nil, 0) if handler.errSetup != nil { diff --git a/clients/githubrepo/graphql_test.go b/clients/githubrepo/graphql_test.go index 0edb5243a6c..1dd95aa9176 100644 --- a/clients/githubrepo/graphql_test.go +++ b/clients/githubrepo/graphql_test.go @@ -35,6 +35,7 @@ func (b badGatewayRoundTripper) RoundTrip(*http.Request) (*http.Response, error) } func Test_getCommits_retry(t *testing.T) { + t.Parallel() var nRequests int rt := badGatewayRoundTripper{requestCounter: &nRequests} handler := graphqlHandler{ diff --git a/clients/githubrepo/internal/fnmatch/fnmatch_test.go b/clients/githubrepo/internal/fnmatch/fnmatch_test.go index 3059568b051..617506a368f 100644 --- a/clients/githubrepo/internal/fnmatch/fnmatch_test.go +++ b/clients/githubrepo/internal/fnmatch/fnmatch_test.go @@ -19,6 +19,7 @@ import ( ) func TestMatch(t *testing.T) { + t.Parallel() tests := []struct { pattern string path string diff --git a/clients/githubrepo/roundtripper/tokens/accessor_test.go b/clients/githubrepo/roundtripper/tokens/accessor_test.go index 129b959cbb4..0996f984b63 100644 --- a/clients/githubrepo/roundtripper/tokens/accessor_test.go +++ b/clients/githubrepo/roundtripper/tokens/accessor_test.go @@ -20,7 +20,7 @@ import ( "testing" ) -//nolint:paralleltest +//nolint:paralleltest // test uses t.Setenv func TestMakeTokenAccessor(t *testing.T) { tests := []struct { name string diff --git a/clients/githubrepo/roundtripper/tokens/round_robin_test.go b/clients/githubrepo/roundtripper/tokens/round_robin_test.go index f6a4e20b18f..ac9e846eed3 100644 --- a/clients/githubrepo/roundtripper/tokens/round_robin_test.go +++ b/clients/githubrepo/roundtripper/tokens/round_robin_test.go @@ -17,7 +17,7 @@ import ( "testing" ) -//golint:paralleltest +//nolint:paralleltest // order dependent func TestNext(t *testing.T) { tokens := []string{"token1", "token2", "token3", "token4", "token5"} rr := makeRoundRobinAccessor(tokens) @@ -35,6 +35,7 @@ func TestNext(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { if tt.releaseID != nil { rr.Release(*tt.releaseID) diff --git a/clients/githubrepo/roundtripper/tokens/rpc_test.go b/clients/githubrepo/roundtripper/tokens/rpc_test.go index 2a0c74b51c4..f8a259a90be 100644 --- a/clients/githubrepo/roundtripper/tokens/rpc_test.go +++ b/clients/githubrepo/roundtripper/tokens/rpc_test.go @@ -45,6 +45,7 @@ func newMockTokenAccessor(tokens []string) *mockTokenAccessor { } func TestTokenOverRPC_Next(t *testing.T) { + t.Parallel() mockClient := newMockTokenAccessor([]string{"token1", "token2", "token3"}) rpc := NewTokenOverRPC(mockClient) token := &Token{} @@ -66,6 +67,7 @@ func TestTokenOverRPC_Next(t *testing.T) { } func TestTokenOverRPC_Release(t *testing.T) { + t.Parallel() mockClient := newMockTokenAccessor([]string{"token1", "token2", "token3"}) rpc := NewTokenOverRPC(mockClient) diff --git a/clients/gitlabrepo/repo_test.go b/clients/gitlabrepo/repo_test.go index a46250de82a..c5f8d0185c8 100644 --- a/clients/gitlabrepo/repo_test.go +++ b/clients/gitlabrepo/repo_test.go @@ -119,6 +119,7 @@ func TestRepoURL_IsValid(t *testing.T) { } func TestRepoURL_MakeGitLabRepo(t *testing.T) { + t.Parallel() tests := []struct { repouri string expected bool diff --git a/clients/ossfuzz/client_test.go b/clients/ossfuzz/client_test.go index dbb856fd139..cb7d455b087 100644 --- a/clients/ossfuzz/client_test.go +++ b/clients/ossfuzz/client_test.go @@ -198,6 +198,7 @@ func setupServer(t *testing.T) string { } func TestAllClientMethods(t *testing.T) { + t.Parallel() c := CreateOSSFuzzClient("testURL") // Test InitRepo diff --git a/cmd/internal/scdiff/app/compare/compare_test.go b/cmd/internal/scdiff/app/compare/compare_test.go index a36146a1a43..3625e650499 100644 --- a/cmd/internal/scdiff/app/compare/compare_test.go +++ b/cmd/internal/scdiff/app/compare/compare_test.go @@ -22,6 +22,7 @@ import ( ) func TestResults(t *testing.T) { + t.Parallel() //nolint:govet // field alignment tests := []struct { name string @@ -213,7 +214,9 @@ func TestResults(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if got := Results(tt.a, tt.b); got != tt.wantEqual { t.Errorf("Results() = %v, want %v", got, tt.wantEqual) } diff --git a/cmd/internal/scdiff/app/format/format_test.go b/cmd/internal/scdiff/app/format/format_test.go index 18c691369c9..f9d11292c0c 100644 --- a/cmd/internal/scdiff/app/format/format_test.go +++ b/cmd/internal/scdiff/app/format/format_test.go @@ -166,6 +166,7 @@ func TestJSON(t *testing.T) { } func Test_normalize_nil_safe(t *testing.T) { + t.Parallel() var x, y *pkg.ScorecardResult Normalize(x) Normalize(y) diff --git a/cmd/internal/scdiff/app/runner/runner_test.go b/cmd/internal/scdiff/app/runner/runner_test.go index 07bfb6135ff..fd79a74400f 100644 --- a/cmd/internal/scdiff/app/runner/runner_test.go +++ b/cmd/internal/scdiff/app/runner/runner_test.go @@ -25,6 +25,7 @@ import ( ) func TestNew(t *testing.T) { + t.Parallel() r := New(nil) if len(r.enabledChecks) == 0 { t.Errorf("runner has no checks to run: %v", r.enabledChecks) @@ -37,6 +38,7 @@ func TestNew(t *testing.T) { } func TestRunner_Run(t *testing.T) { + t.Parallel() ctrl := gomock.NewController(t) mockRepo := mockrepo.NewMockRepoClient(ctrl) commit := []clients.Commit{{SHA: "foo"}} diff --git a/dependencydiff/dependencydiff_test.go b/dependencydiff/dependencydiff_test.go index 3717371af0a..80e59c01ac7 100644 --- a/dependencydiff/dependencydiff_test.go +++ b/dependencydiff/dependencydiff_test.go @@ -25,6 +25,7 @@ import ( ) func Test_initRepoAndClientByChecks(t *testing.T) { + t.Parallel() //nolint:govet tests := []struct { name string @@ -57,6 +58,7 @@ func Test_initRepoAndClientByChecks(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := initRepoAndClientByChecks(&tt.dCtx, tt.srcRepo) if (err != nil) != tt.wantErr { t.Errorf("initClientByChecks() error = {%v}, want error: %v", err, tt.wantErr) @@ -83,6 +85,7 @@ func Test_initRepoAndClientByChecks(t *testing.T) { } func Test_getScorecardCheckResults(t *testing.T) { + t.Parallel() tests := []struct { name string dCtx dependencydiffContext @@ -102,6 +105,7 @@ func Test_getScorecardCheckResults(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := getScorecardCheckResults(&tt.dCtx) if (err != nil) != tt.wantErr { t.Errorf("getScorecardCheckResults() error = {%v}, want error: %v", err, tt.wantErr) @@ -112,6 +116,7 @@ func Test_getScorecardCheckResults(t *testing.T) { } func Test_mapDependencyEcosystemNaming(t *testing.T) { + t.Parallel() //nolint:govet tests := []struct { name string @@ -167,6 +172,7 @@ func Test_mapDependencyEcosystemNaming(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := mapDependencyEcosystemNaming(tt.deps) if tt.errWanted != nil && errors.Is(tt.errWanted, err) { t.Errorf("not a wanted error, want:%v, got:%v", tt.errWanted, err) @@ -177,6 +183,7 @@ func Test_mapDependencyEcosystemNaming(t *testing.T) { } func Test_isSpecifiedByUser(t *testing.T) { + t.Parallel() tests := []struct { name string ct pkg.ChangeType @@ -214,6 +221,7 @@ func Test_isSpecifiedByUser(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() result := isSpecifiedByUser(tt.ct, tt.changeTypesToCheck) if result != tt.resultWanted { t.Errorf("result (%v) != result wanted (%v)", result, tt.resultWanted) diff --git a/e2e/e2e_suite_test.go b/e2e/e2e_suite_test.go index efe1125a938..e1f59f2e84f 100644 --- a/e2e/e2e_suite_test.go +++ b/e2e/e2e_suite_test.go @@ -25,6 +25,7 @@ import ( "github.com/ossf/scorecard/v4/log" ) +//nolint:paralleltest // avoiding parallel e2e tests due to rate limit concerns (#2527) func TestE2e(t *testing.T) { if val, exists := os.LookupEnv("SKIP_GINKGO"); exists && val == "1" { t.Skip() diff --git a/errors/internal_test.go b/errors/internal_test.go index b1ea3b74a69..e83c3dd0a25 100644 --- a/errors/internal_test.go +++ b/errors/internal_test.go @@ -21,6 +21,7 @@ import ( ) func TestCreateInternal(t *testing.T) { + t.Parallel() type args struct { e error msg string @@ -39,6 +40,7 @@ func TestCreateInternal(t *testing.T) { } t.Run(test.name, func(t *testing.T) { + t.Parallel() if got := CreateInternal(test.args.e, test.args.msg); got.Error() != test.want.Error() { t.Errorf("CreateInternal() = %v, want %v", got, test.want) } diff --git a/pkg/json_raw_results_test.go b/pkg/json_raw_results_test.go index 7b489c324d0..d9391c8c55e 100644 --- a/pkg/json_raw_results_test.go +++ b/pkg/json_raw_results_test.go @@ -472,6 +472,7 @@ func TestJsonScorecardRawResult_AddMaintainedRawResults(t *testing.T) { } func TestSetDefaultCommitData(t *testing.T) { + t.Parallel() // Define some test data. changesets := []checker.Changeset{ { @@ -657,6 +658,7 @@ func TestJsonScorecardRawResult_AddCodeReviewRawResults(t *testing.T) { } func TestAddCodeReviewRawResults(t *testing.T) { + t.Parallel() r := &jsonScorecardRawResult{} cr := &checker.CodeReviewData{ DefaultBranchChangesets: []checker.Changeset{ @@ -729,6 +731,7 @@ func TestAddCodeReviewRawResults(t *testing.T) { } func TestAddLicenseRawResults(t *testing.T) { + t.Parallel() // Create a new jsonScorecardRawResult instance r := &jsonScorecardRawResult{} @@ -793,6 +796,7 @@ func TestAddLicenseRawResults(t *testing.T) { } func TestAddBinaryArtifactRawResults(t *testing.T) { + t.Parallel() r := &jsonScorecardRawResult{} ba := &checker.BinaryArtifactData{ Files: []checker.File{ @@ -831,6 +835,7 @@ func TestAddBinaryArtifactRawResults(t *testing.T) { } func TestAddSecurityPolicyRawResults(t *testing.T) { + t.Parallel() r := &jsonScorecardRawResult{} sp := &checker.SecurityPolicyData{ PolicyFiles: []checker.SecurityPolicyFile{ @@ -917,6 +922,7 @@ func TestAddSecurityPolicyRawResults(t *testing.T) { } func TestAddVulnerabilitiesRawResults(t *testing.T) { + t.Parallel() r := &jsonScorecardRawResult{} vd := &checker.VulnerabilitiesData{ Vulnerabilities: []clients.Vulnerability{ @@ -955,6 +961,7 @@ func TestAddVulnerabilitiesRawResults(t *testing.T) { } func TestAddFuzzingRawResults(t *testing.T) { + t.Parallel() r := &jsonScorecardRawResult{} fd := &checker.FuzzingData{ Fuzzers: []checker.Tool{ @@ -1040,6 +1047,7 @@ func TestAddFuzzingRawResults(t *testing.T) { } func TestJsonScorecardRawResult(t *testing.T) { + t.Parallel() // create a new instance of jsonScorecardRawResult r := &jsonScorecardRawResult{} @@ -1225,6 +1233,7 @@ func intPtr(i int32) *int32 { } func TestScorecardResult_AsRawJSON(t *testing.T) { + t.Parallel() type fields struct { Repo RepoInfo Date time.Time @@ -1254,6 +1263,7 @@ func TestScorecardResult_AsRawJSON(t *testing.T) { for _, tt := range tests { tt := tt // capture range variable t.Run(tt.name, func(t *testing.T) { + t.Parallel() r := &ScorecardResult{ Repo: tt.fields.Repo, Date: tt.fields.Date, @@ -1343,6 +1353,7 @@ func TestAddBranchProtectionRawResults(t *testing.T) { } func TestFillJSONRawResults(t *testing.T) { + t.Parallel() raw := checker.RawResults{ LicenseResults: checker.LicenseData{ LicenseFiles: []checker.LicenseFile{ diff --git a/pkg/pkg_suite_test.go b/pkg/pkg_suite_test.go index c89786b1eb9..1e143d76c60 100644 --- a/pkg/pkg_suite_test.go +++ b/pkg/pkg_suite_test.go @@ -22,6 +22,7 @@ import ( . "github.com/onsi/gomega" ) +//nolint:paralleltest // avoiding parallel e2e tests due to rate limit concerns (#2527) func TestPkg(t *testing.T) { if val, exists := os.LookupEnv("SKIP_GINKGO"); exists && val == "1" { t.Skip() diff --git a/policy/policy_test.go b/policy/policy_test.go index 5fec445f73f..7c77f23071b 100644 --- a/policy/policy_test.go +++ b/policy/policy_test.go @@ -137,6 +137,7 @@ func TestPolicyRead(t *testing.T) { } func TestChecksHavePolicies(t *testing.T) { + t.Parallel() // Create a sample ScorecardPolicy sp := &ScorecardPolicy{ Version: 1, From e4fc8150b04821fb16a86b7e2a0fa4feb9b75f0b Mon Sep 17 00:00:00 2001 From: Allen Shearin Date: Mon, 4 Dec 2023 10:59:02 -0700 Subject: [PATCH 31/51] =?UTF-8?q?=F0=9F=90=9B=20Parse=20Gitlab=20Status=20?= =?UTF-8?q?fields=20to=20align=20w/Github=20Status=20and=20Conclusion=20(#?= =?UTF-8?q?3706)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: parse gitlab pipeline status to their GitHub equivalent Signed-off-by: Allen Shearin * change completed string to const Signed-off-by: Allen Shearin --------- Signed-off-by: Allen Shearin --- clients/gitlabrepo/checkruns.go | 40 ++++++++- clients/gitlabrepo/checkruns_test.go | 124 ++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 5 deletions(-) diff --git a/clients/gitlabrepo/checkruns.go b/clients/gitlabrepo/checkruns.go index 5744b1df052..80f62546e11 100644 --- a/clients/gitlabrepo/checkruns.go +++ b/clients/gitlabrepo/checkruns.go @@ -50,10 +50,42 @@ func checkRunsFrom(data []*gitlab.PipelineInfo) []clients.CheckRun { for _, pipelineInfo := range data { // TODO: Can get more info from GitLab API here (e.g. pipeline name, URL) // https://docs.gitlab.com/ee/api/pipelines.html#get-a-pipelines-test-report - checkRuns = append(checkRuns, clients.CheckRun{ - Status: pipelineInfo.Status, - URL: pipelineInfo.WebURL, - }) + checkRuns = append(checkRuns, parseGitlabStatus(pipelineInfo)) } return checkRuns } + +// Conclusion does not exist in the pipelines for gitlab, +// so we parse the status to determine the conclusion if it exists. +func parseGitlabStatus(info *gitlab.PipelineInfo) clients.CheckRun { + checkrun := clients.CheckRun{ + URL: info.WebURL, + } + const completed = "completed" + + switch info.Status { + case "created", "waiting_for_resource", "preparing", "pending", "scheduled": + checkrun.Status = "queued" + case "running": + checkrun.Status = "in_progress" + case "failed": + checkrun.Status = completed + checkrun.Conclusion = "failure" + case "success": + checkrun.Status = completed + checkrun.Conclusion = "success" + case "canceled": + checkrun.Status = completed + checkrun.Conclusion = "cancelled" + case "skipped": + checkrun.Status = completed + checkrun.Conclusion = "skipped" + case "manual": + checkrun.Status = completed + checkrun.Conclusion = "action_required" + default: + checkrun.Status = info.Status + } + + return checkrun +} diff --git a/clients/gitlabrepo/checkruns_test.go b/clients/gitlabrepo/checkruns_test.go index 2ff87a4925e..c11ff2b5408 100644 --- a/clients/gitlabrepo/checkruns_test.go +++ b/clients/gitlabrepo/checkruns_test.go @@ -37,7 +37,7 @@ func Test_CheckRuns(t *testing.T) { responsePath: "./testdata/valid-checkruns", want: []clients.CheckRun{ { - Status: "pending", + Status: "queued", URL: "https://example.com/foo/bar/pipelines/48", Conclusion: "", }, @@ -88,3 +88,125 @@ func Test_CheckRuns(t *testing.T) { }) } } + +func TestParseGitlabStatus(t *testing.T) { + t.Parallel() + tests := []struct { + status string + want clients.CheckRun + }{ + { + status: "created", + want: clients.CheckRun{ + Status: "queued", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + { + status: "waiting_for_resource", + want: clients.CheckRun{ + Status: "queued", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + { + status: "preparing", + want: clients.CheckRun{ + Status: "queued", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + { + status: "pending", + want: clients.CheckRun{ + Status: "queued", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + { + status: "scheduled", + want: clients.CheckRun{ + Status: "queued", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + { + status: "running", + want: clients.CheckRun{ + Status: "in_progress", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + { + status: "failed", + want: clients.CheckRun{ + Status: "completed", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "failure", + }, + }, + { + status: "success", + want: clients.CheckRun{ + Status: "completed", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "success", + }, + }, + { + status: "canceled", + want: clients.CheckRun{ + Status: "completed", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "cancelled", + }, + }, + { + status: "skipped", + want: clients.CheckRun{ + Status: "completed", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "skipped", + }, + }, + { + status: "manual", + want: clients.CheckRun{ + Status: "completed", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "action_required", + }, + }, + { + status: "invalid_status", + want: clients.CheckRun{ + Status: "invalid_status", + URL: "https://example.com/foo/bar/pipelines/48", + Conclusion: "", + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.status, func(t *testing.T) { + t.Parallel() + + info := gitlab.PipelineInfo{ + WebURL: "https://example.com/foo/bar/pipelines/48", + Status: tt.status, + } + + got := parseGitlabStatus(&info) + + if !cmp.Equal(got, tt.want) { + t.Errorf("parseGitlabStatus() = %v, want %v", got, cmp.Diff(got, tt.want)) + } + }) + } +} From 7656dc7e4ee67aea6f0cb4b23b83f6eb6cbd8150 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 18:56:30 +0000 Subject: [PATCH 32/51] :seedling: Bump github.com/onsi/ginkgo/v2 in /tools (#3703) Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.1 to 2.13.2. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.1...v2.13.2) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/go.mod | 2 +- tools/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index 24251fe5083..10747a05ddb 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -8,7 +8,7 @@ require ( github.com/google/addlicense v1.1.1 github.com/google/ko v0.15.1 github.com/goreleaser/goreleaser v1.20.0 - github.com/onsi/ginkgo/v2 v2.13.1 + github.com/onsi/ginkgo/v2 v2.13.2 google.golang.org/protobuf v1.31.0 ) diff --git a/tools/go.sum b/tools/go.sum index 80e0a08bdce..c9814b7a932 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -889,8 +889,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= -github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= +github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= +github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= From 483cc31b60c63cc7e13a9b4211ff6acf8b4d7d20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 14:39:48 -0800 Subject: [PATCH 33/51] :seedling: Bump github.com/moby/buildkit from 0.12.3 to 0.12.4 (#3710) Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.3 to 0.12.4. - [Release notes](https://github.com/moby/buildkit/releases) - [Commits](https://github.com/moby/buildkit/compare/v0.12.3...v0.12.4) --- updated-dependencies: - dependency-name: github.com/moby/buildkit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0b304f864e8..6637d9ecbe7 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/grafeas/kritis v0.2.3-0.20210120183821-faeba81c520c github.com/h2non/filetype v1.1.3 github.com/jszwec/csvutil v1.8.0 - github.com/moby/buildkit v0.12.3 + github.com/moby/buildkit v0.12.4 github.com/olekukonko/tablewriter v0.0.5 github.com/onsi/gomega v1.30.0 github.com/rhysd/actionlint v1.6.26 @@ -156,7 +156,7 @@ require ( github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect diff --git a/go.sum b/go.sum index 026b5204e92..3353fbf9861 100644 --- a/go.sum +++ b/go.sum @@ -537,8 +537,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -593,8 +593,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/moby/buildkit v0.12.3 h1:cFaPVnyC0PwAP5xHHfzdU5v9rgQrCi6HnGSg3WuFKp4= -github.com/moby/buildkit v0.12.3/go.mod h1:adB4y0SxxX8trnrY+oEulb48ODLqPO6pKMF0ppGcCoI= +github.com/moby/buildkit v0.12.4 h1:yKZDsObXLKarXqUx7YMnaB+TKv810bBhq0XLFWbkjT0= +github.com/moby/buildkit v0.12.4/go.mod h1:XG74uz06nPWQpnxYwgCryrVidvor0+ElUxGosbZPQG4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From cb721a8526fccd47bc234d9d2005eecd01e4b0ae Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:24:16 +0000 Subject: [PATCH 34/51] :seedling: convert binary artifact check to probe (#3508) * :seedling: convert binary artifact check to probe Signed-off-by: AdamKorcz * Reword motivation Signed-off-by: AdamKorcz * remove unused variable in test Signed-off-by: AdamKorcz * remove positiveOutcome() and length check Signed-off-by: AdamKorcz * fix wrong check name Signed-off-by: AdamKorcz * Split into two probes: One with and one without gradle-wrappers Signed-off-by: AdamKorcz * Add description about what Scorecard considers a verified binary Signed-off-by: Adam Korczynski * change 'trusted' to 'verified' Signed-off-by: Adam Korczynski * remove nil check Signed-off-by: Adam Korczynski * remove filtering Signed-off-by: Adam Korczynski * use const scores in tests Signed-off-by: Adam Korczynski * rename test Signed-off-by: Adam Korczynski * add sanity check in loop Signed-off-by: Adam Korczynski * rename binary file const Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- checks/binary_artifact.go | 19 +- checks/evaluation/binary_artifacts.go | 37 +- checks/evaluation/binary_artifacts_test.go | 330 +++++------------- checks/raw/binary_artifact.go | 11 +- checks/raw/binary_artifact_test.go | 25 +- finding/finding.go | 2 + probes/entries.go | 4 + probes/freeOfAnyBinaryArtifacts/def.yml | 28 ++ probes/freeOfAnyBinaryArtifacts/impl.go | 66 ++++ probes/freeOfAnyBinaryArtifacts/impl_test.go | 158 +++++++++ .../freeOfUnverifiedBinaryArtifacts/def.yml | 28 ++ .../freeOfUnverifiedBinaryArtifacts/impl.go | 69 ++++ .../impl_test.go | 123 +++++++ 13 files changed, 637 insertions(+), 263 deletions(-) create mode 100644 probes/freeOfAnyBinaryArtifacts/def.yml create mode 100644 probes/freeOfAnyBinaryArtifacts/impl.go create mode 100644 probes/freeOfAnyBinaryArtifacts/impl_test.go create mode 100644 probes/freeOfUnverifiedBinaryArtifacts/def.yml create mode 100644 probes/freeOfUnverifiedBinaryArtifacts/impl.go create mode 100644 probes/freeOfUnverifiedBinaryArtifacts/impl_test.go diff --git a/checks/binary_artifact.go b/checks/binary_artifact.go index 63a7ec98794..f57d154524f 100644 --- a/checks/binary_artifact.go +++ b/checks/binary_artifact.go @@ -19,6 +19,8 @@ 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" + "github.com/ossf/scorecard/v4/probes/zrunner" ) // CheckBinaryArtifacts is the exported name for Binary-Artifacts check. @@ -38,17 +40,22 @@ func init() { // BinaryArtifacts will check the repository contains binary artifacts. func BinaryArtifacts(c *checker.CheckRequest) checker.CheckResult { - rawData, err := raw.BinaryArtifacts(c.RepoClient) + rawData, err := raw.BinaryArtifacts(c) if err != nil { e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) return checker.CreateRuntimeErrorResult(CheckBinaryArtifacts, e) } - // Return raw results. - if c.RawResults != nil { - c.RawResults.BinaryArtifactResults = rawData + // Set the raw results. + pRawResults := getRawResults(c) + pRawResults.BinaryArtifactResults = rawData + + // Evaluate the probes. + findings, err := zrunner.Run(pRawResults, probes.BinaryArtifacts) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckBinaryArtifacts, e) } - // Return the score evaluation. - return evaluation.BinaryArtifacts(CheckBinaryArtifacts, c.Dlogger, &rawData) + return evaluation.BinaryArtifacts(CheckBinaryArtifacts, findings, c.Dlogger) } diff --git a/checks/evaluation/binary_artifacts.go b/checks/evaluation/binary_artifacts.go index 59075912844..fff943fb2a1 100644 --- a/checks/evaluation/binary_artifacts.go +++ b/checks/evaluation/binary_artifacts.go @@ -18,33 +18,46 @@ import ( "github.com/ossf/scorecard/v4/checker" sce "github.com/ossf/scorecard/v4/errors" "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/freeOfUnverifiedBinaryArtifacts" ) // BinaryArtifacts applies the score policy for the Binary-Artifacts check. -func BinaryArtifacts(name string, dl checker.DetailLogger, - r *checker.BinaryArtifactData, +func BinaryArtifacts(name string, + findings []finding.Finding, + dl checker.DetailLogger, ) checker.CheckResult { - if r == nil { - e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") + expectedProbes := []string{ + freeOfUnverifiedBinaryArtifacts.Probe, + } + + if !finding.UniqueProbesEqual(findings, expectedProbes) { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results") return checker.CreateRuntimeErrorResult(name, e) } - // Apply the policy evaluation. - if r.Files == nil || len(r.Files) == 0 { + if findings[0].Outcome == finding.OutcomePositive { return checker.CreateMaxScoreResult(name, "no binaries found in the repo") } - score := checker.MaxResultScore - for _, f := range r.Files { + for i := range findings { + f := &findings[i] + if f.Outcome != finding.OutcomeNegative { + continue + } dl.Warn(&checker.LogMessage{ - Path: f.Path, Type: finding.FileTypeBinary, - Offset: f.Offset, + Path: f.Location.Path, + Type: f.Location.Type, + Offset: *f.Location.LineStart, Text: "binary detected", }) - // We remove one point for each binary. - score-- } + // There are only negative findings. + // Deduct the number of findings from max score + numberOfBinaryFilesFound := len(findings) + + score := checker.MaxResultScore - numberOfBinaryFilesFound + if score < checker.MinResultScore { score = checker.MinResultScore } diff --git a/checks/evaluation/binary_artifacts_test.go b/checks/evaluation/binary_artifacts_test.go index ed7a0fa95a7..d2f9c4f8727 100644 --- a/checks/evaluation/binary_artifacts_test.go +++ b/checks/evaluation/binary_artifacts_test.go @@ -18,256 +18,121 @@ 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" ) // TestBinaryArtifacts tests the binary artifacts check. func TestBinaryArtifacts(t *testing.T) { t.Parallel() - //nolint:govet - type args struct { - name string - dl checker.DetailLogger - r *checker.BinaryArtifactData + lineStart := uint(123) + negativeFinding := finding.Finding{ + Probe: "freeOfUnverifiedBinaryArtifacts", + Outcome: finding.OutcomeNegative, + + Location: &finding.Location{ + Path: "path", + Type: finding.FileTypeBinary, + LineStart: &lineStart, + }, } + tests := []struct { - name string - args args - want checker.CheckResult - wantErr bool + name string + findings []finding.Finding + result scut.TestReturn }{ { - name: "r nil", - args: args{ - name: "test_binary_artifacts_check_pass", - dl: &scut.TestDetailLogger{}, + name: "no binary artifacts", + findings: []finding.Finding{ + { + Probe: "freeOfUnverifiedBinaryArtifacts", + Outcome: finding.OutcomePositive, + }, + }, + result: scut.TestReturn{ + Score: checker.MaxResultScore, }, - wantErr: true, }, { - name: "no binary artifacts", - args: args{ - name: "no binary artifacts", - dl: &scut.TestDetailLogger{}, - r: &checker.BinaryArtifactData{}, + name: "one binary artifact", + findings: []finding.Finding{ + negativeFinding, }, - want: checker.CheckResult{ - Score: checker.MaxResultScore, + result: scut.TestReturn{ + Score: 9, + NumberOfWarn: 1, }, }, { - name: "1 binary artifact", - args: args{ - name: "no binary artifacts", - dl: &scut.TestDetailLogger{}, - r: &checker.BinaryArtifactData{ - Files: []checker.File{ - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, + name: "two binary artifact", + findings: []finding.Finding{ + { + Probe: "freeOfUnverifiedBinaryArtifacts", + Outcome: finding.OutcomeNegative, + Location: &finding.Location{ + Path: "path", + Type: finding.FileTypeBinary, + LineStart: &lineStart, + }, + }, + { + Probe: "freeOfUnverifiedBinaryArtifacts", + Outcome: finding.OutcomeNegative, + Location: &finding.Location{ + Path: "path", + Type: finding.FileTypeBinary, + LineStart: &lineStart, }, }, }, - want: checker.CheckResult{ - Score: 9, + result: scut.TestReturn{ + Score: 8, + NumberOfWarn: 2, }, }, { - name: "many binary artifact", - args: args{ - name: "no binary artifacts", - dl: &scut.TestDetailLogger{}, - r: &checker.BinaryArtifactData{ - Files: []checker.File{ - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - { - Path: "test_binary_artifacts_check_pass", - Snippet: ` - package main - import "fmt" - func main() { - fmt.Println("Hello, world!") - }i`, - Offset: 0, - Type: 0, - }, - }, - }, + name: "five binary artifact", + findings: []finding.Finding{ + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + }, + result: scut.TestReturn{ + Score: 5, + NumberOfWarn: 5, + }, + }, + { + name: "twelve binary artifact - ensure score doesn't drop below min", + findings: []finding.Finding{ + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + negativeFinding, + }, + result: scut.TestReturn{ + Score: checker.MinResultScore, + NumberOfWarn: 12, }, - want: checker.CheckResult{ - Score: 0, + }, + { + name: "invalid findings", + findings: []finding.Finding{}, + result: scut.TestReturn{ + Score: checker.InconclusiveResultScore, + Error: sce.ErrScorecardInternal, }, }, } @@ -275,15 +140,10 @@ func TestBinaryArtifacts(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - got := BinaryArtifacts(tt.args.name, tt.args.dl, tt.args.r) - if tt.wantErr { - if got.Error == nil { - t.Errorf("BinaryArtifacts() error = %v, wantErr %v", got.Error, tt.wantErr) - } - } else { - if got.Score != tt.want.Score { - t.Errorf("BinaryArtifacts() = %v, want %v", got.Score, tt.want.Score) - } + dl := scut.TestDetailLogger{} + got := BinaryArtifacts(tt.name, tt.findings, &dl) + if !scut.ValidateTestReturn(t, tt.name, &tt.result, &got, &dl) { + t.Errorf("got %v, expected %v", got, tt.result) } }) } diff --git a/checks/raw/binary_artifact.go b/checks/raw/binary_artifact.go index 03c129b5727..c2fc925c097 100644 --- a/checks/raw/binary_artifact.go +++ b/checks/raw/binary_artifact.go @@ -49,7 +49,8 @@ func mustParseConstraint(c string) *semver.Constraints { } // BinaryArtifacts retrieves the raw data for the Binary-Artifacts check. -func BinaryArtifacts(c clients.RepoClient) (checker.BinaryArtifactData, error) { +func BinaryArtifacts(req *checker.CheckRequest) (checker.BinaryArtifactData, error) { + c := req.RepoClient files := []checker.File{} err := fileparser.OnMatchingFileContentDo(c, fileparser.PathMatcher{ Pattern: "*", @@ -87,13 +88,11 @@ func excludeValidatedGradleWrappers(c clients.RepoClient, files []checker.File) } // It has been confirmed that latest commit has validated JARs! // Remove Gradle wrapper JARs from files. - filterFiles := []checker.File{} - for _, f := range files { - if filepath.Base(f.Path) != "gradle-wrapper.jar" { - filterFiles = append(filterFiles, f) + for i := range files { + if filepath.Base(files[i].Path) == "gradle-wrapper.jar" { + files[i].Type = finding.FileTypeBinaryVerified } } - files = filterFiles return files, nil } diff --git a/checks/raw/binary_artifact_test.go b/checks/raw/binary_artifact_test.go index ace73e34f69..22362c40c19 100644 --- a/checks/raw/binary_artifact_test.go +++ b/checks/raw/binary_artifact_test.go @@ -21,8 +21,10 @@ import ( "github.com/golang/mock/gomock" + "github.com/ossf/scorecard/v4/checker" "github.com/ossf/scorecard/v4/clients" mockrepo "github.com/ossf/scorecard/v4/clients/mockclients" + scut "github.com/ossf/scorecard/v4/utests" ) func strptr(s string) *string { @@ -126,7 +128,7 @@ func TestBinaryArtifacts(t *testing.T) { }, }, getFileContentCount: 3, - expect: 0, + expect: 1, }, { name: "gradle-wrapper.jar with non-verification action", @@ -210,7 +212,7 @@ func TestBinaryArtifacts(t *testing.T) { }, }, getFileContentCount: 3, - expect: 0, + expect: 1, }, } for _, tt := range tests { @@ -220,6 +222,7 @@ func TestBinaryArtifacts(t *testing.T) { ctrl := gomock.NewController(t) mockRepoClient := mockrepo.NewMockRepoClient(ctrl) + mockRepo := mockrepo.NewMockRepo(ctrl) for _, files := range tt.files { mockRepoClient.EXPECT().ListFiles(gomock.Any()).Return(files, nil) } @@ -240,7 +243,14 @@ func TestBinaryArtifacts(t *testing.T) { mockRepoClient.EXPECT().ListCommits().Return(tt.commits, nil) } - f, err := BinaryArtifacts(mockRepoClient) + dl := scut.TestDetailLogger{} + c := &checker.CheckRequest{ + RepoClient: mockRepoClient, + Repo: mockRepo, + Dlogger: &dl, + } + + f, err := BinaryArtifacts(c) if tt.err != nil { // If we expect an error, make sure it is the same @@ -261,6 +271,7 @@ func TestBinaryArtifacts_workflow_runs_unsupported(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) mockRepoClient := mockrepo.NewMockRepoClient(ctrl) + mockRepo := mockrepo.NewMockRepo(ctrl) const jarFile = "gradle-wrapper.jar" const verifyWorkflow = ".github/workflows/verify.yaml" files := []string{jarFile, verifyWorkflow} @@ -281,7 +292,13 @@ func TestBinaryArtifacts_workflow_runs_unsupported(t *testing.T) { }).AnyTimes() mockRepoClient.EXPECT().ListSuccessfulWorkflowRuns(gomock.Any()).Return(nil, clients.ErrUnsupportedFeature).AnyTimes() - got, err := BinaryArtifacts(mockRepoClient) + dl := scut.TestDetailLogger{} + c := &checker.CheckRequest{ + RepoClient: mockRepoClient, + Repo: mockRepo, + Dlogger: &dl, + } + got, err := BinaryArtifacts(c) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/finding/finding.go b/finding/finding.go index 39f06175cee..761fb876f16 100644 --- a/finding/finding.go +++ b/finding/finding.go @@ -40,6 +40,8 @@ const ( FileTypeText // FileTypeURL for URLs. FileTypeURL + // FileTypeBinaryVerified for verified binary files. + FileTypeBinaryVerified ) // Location represents the location of a finding. diff --git a/probes/entries.go b/probes/entries.go index b5600ebe7e2..c9d125f81e5 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -18,6 +18,7 @@ import ( "github.com/ossf/scorecard/v4/checker" "github.com/ossf/scorecard/v4/finding" "github.com/ossf/scorecard/v4/probes/contributorsFromOrgOrCompany" + "github.com/ossf/scorecard/v4/probes/freeOfUnverifiedBinaryArtifacts" "github.com/ossf/scorecard/v4/probes/fuzzedWithCLibFuzzer" "github.com/ossf/scorecard/v4/probes/fuzzedWithClusterFuzzLite" "github.com/ossf/scorecard/v4/probes/fuzzedWithCppLibFuzzer" @@ -121,6 +122,9 @@ var ( CIIBestPractices = []ProbeImpl{ hasOpenSSFBadge.Run, } + BinaryArtifacts = []ProbeImpl{ + freeOfUnverifiedBinaryArtifacts.Run, + } ) //nolint:gochecknoinits diff --git a/probes/freeOfAnyBinaryArtifacts/def.yml b/probes/freeOfAnyBinaryArtifacts/def.yml new file mode 100644 index 00000000000..858a882f45c --- /dev/null +++ b/probes/freeOfAnyBinaryArtifacts/def.yml @@ -0,0 +1,28 @@ +# 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: freeOfAnyBinaryArtifacts +short: Checks if the project has any binary files in its source tree. +motivation: > + Binary files are not readable so users can't see what they do. Many programming language systems can generate executables from source code (e.g., C/C++ generated machine code, Java .class files, Python .pyc files, and minified JavaScript). Users will often directly use executables if they are included in the source repository, leading to many dangerous behaviors. +implementation: > + The implementation looks for the presence of binary files. This is a more restrictive probe than "freeOfUnverifiededBinaryArtifacts" which excludes verified binary files. +outcome: + - If the probe finds binary files, it returns a number of negative outcomes equal to the number of binary files found. Each outcome includes a location of the file. + - If the probe finds no verified binary files, it returns a single positive outcome. +remediation: + effort: Medium + text: + - Remove the generated executable artifacts from the repository. + - Build from source. diff --git a/probes/freeOfAnyBinaryArtifacts/impl.go b/probes/freeOfAnyBinaryArtifacts/impl.go new file mode 100644 index 00000000000..19df5a131c4 --- /dev/null +++ b/probes/freeOfAnyBinaryArtifacts/impl.go @@ -0,0 +1,66 @@ +// 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. + +//nolint:stylecheck +package freeOfAnyBinaryArtifacts + +import ( + "embed" + "fmt" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const Probe = "freeOfAnyBinaryArtifacts" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.BinaryArtifactResults + var findings []finding.Finding + + // Apply the policy evaluation. + if len(r.Files) == 0 { + f, err := finding.NewWith(fs, Probe, + "Repository does not have any binary artifacts.", nil, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + for i := range r.Files { + file := &r.Files[i] + f, err := finding.NewWith(fs, Probe, "binary artifact detected", + nil, finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithLocation(&finding.Location{ + Path: file.Path, + LineStart: &file.Offset, + Type: file.Type, + }) + findings = append(findings, *f) + } + + return findings, Probe, nil +} diff --git a/probes/freeOfAnyBinaryArtifacts/impl_test.go b/probes/freeOfAnyBinaryArtifacts/impl_test.go new file mode 100644 index 00000000000..94046cb5fb7 --- /dev/null +++ b/probes/freeOfAnyBinaryArtifacts/impl_test.go @@ -0,0 +1,158 @@ +// 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. + +//nolint:stylecheck +package freeOfAnyBinaryArtifacts + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "1 binary artifact", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{ + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + }, + }, + { + name: "No binary artifacts", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{}, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "many binary artifact", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{ + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomeNegative, + finding.OutcomeNegative, + }, + }, + { + name: "many binary artifact including gradle wrappers", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{ + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "gradle-wrapper.jar", + Type: finding.FileTypeBinaryVerified, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomeNegative, + finding.OutcomeNegative, + finding.OutcomeNegative, + }, + }, + { + name: "Is free of any binary artifacts", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{}, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} diff --git a/probes/freeOfUnverifiedBinaryArtifacts/def.yml b/probes/freeOfUnverifiedBinaryArtifacts/def.yml new file mode 100644 index 00000000000..871475ea7be --- /dev/null +++ b/probes/freeOfUnverifiedBinaryArtifacts/def.yml @@ -0,0 +1,28 @@ +# 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: freeOfUnverifiedBinaryArtifacts +short: Checks if the project has binary files in its source tree. The probe skips verified binary files which currently are gradle-wrappers. +motivation: > + Binary files are not readable so users can't see what they do. Many programming language systems can generate executables from source code (e.g., C/C++ generated machine code, Java .class files, Python .pyc files, and minified JavaScript). Users will often directly use executables if they are included in the source repository, leading to many dangerous behaviors. +implementation: > + The implementation looks for the presence of binary files that are not "verified". A verified binary is one that Scorecard considers valid for building and/or releasing the project. This is a more permissive probe than "freeOfAnyBinaryArtifacts" which does not skip verified binary files. +outcome: + - If the probe finds unverified binary files, it returns a number of negative outcomes equal to the number of unverified binary files found. Each outcome includes a location of the file. + - If the probe finds no unverified binary files, it returns a single positive outcome. +remediation: + effort: Medium + text: + - Remove the generated executable artifacts from the repository. + - Build from source. diff --git a/probes/freeOfUnverifiedBinaryArtifacts/impl.go b/probes/freeOfUnverifiedBinaryArtifacts/impl.go new file mode 100644 index 00000000000..ad934e50498 --- /dev/null +++ b/probes/freeOfUnverifiedBinaryArtifacts/impl.go @@ -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. + +//nolint:stylecheck +package freeOfUnverifiedBinaryArtifacts + +import ( + "embed" + "fmt" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const Probe = "freeOfUnverifiedBinaryArtifacts" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.BinaryArtifactResults + + var findings []finding.Finding + + for i := range r.Files { + file := &r.Files[i] + if file.Type == finding.FileTypeBinaryVerified { + continue + } + f, err := finding.NewWith(fs, Probe, "binary artifact detected", + nil, finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithLocation(&finding.Location{ + Path: file.Path, + LineStart: &file.Offset, + Type: file.Type, + }) + findings = append(findings, *f) + } + + if len(findings) == 0 { + f, err := finding.NewWith(fs, Probe, + "Repository does not have binary artifacts.", nil, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + return findings, Probe, nil +} diff --git a/probes/freeOfUnverifiedBinaryArtifacts/impl_test.go b/probes/freeOfUnverifiedBinaryArtifacts/impl_test.go new file mode 100644 index 00000000000..ce03d7400bc --- /dev/null +++ b/probes/freeOfUnverifiedBinaryArtifacts/impl_test.go @@ -0,0 +1,123 @@ +// 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. + +//nolint:stylecheck +package freeOfUnverifiedBinaryArtifacts + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "1 binary artifact", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{ + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + }, + }, + { + name: "Two binary artifacts and one gradle wrapper (which is trusted)", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{ + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinary, + }, + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinaryVerified, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomeNegative, + }, + }, + { + name: "One gradle wrapper (which is trusted)", + raw: &checker.RawResults{ + BinaryArtifactResults: checker.BinaryArtifactData{ + Files: []checker.File{ + { + Path: "test_binary_artifacts_check_pass", + Type: finding.FileTypeBinaryVerified, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} From c089856d5f28f3ade0a9f43026242f54c10c4341 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Tue, 5 Dec 2023 08:18:57 -0800 Subject: [PATCH 35/51] remove ununsed directives (#3713) Signed-off-by: Spencer Schrock --- checks/raw/shell_download_validate_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/checks/raw/shell_download_validate_test.go b/checks/raw/shell_download_validate_test.go index 44dfe065154..05e23e10529 100644 --- a/checks/raw/shell_download_validate_test.go +++ b/checks/raw/shell_download_validate_test.go @@ -388,7 +388,7 @@ func Test_hasUnpinnedURLs(t *testing.T) { "wget", "-0", "-", - "https://raw.githubusercontent.com/dotnet/install-scripts/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/src/dotnet-install.sh", //nolint:lll + "https://raw.githubusercontent.com/dotnet/install-scripts/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/src/dotnet-install.sh", }, }, expected: true, @@ -412,7 +412,7 @@ func Test_hasUnpinnedURLs(t *testing.T) { "wget", "-0", "-", - "https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", //nolint:lll + "https://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", }, }, expected: false, @@ -424,7 +424,7 @@ func Test_hasUnpinnedURLs(t *testing.T) { "wget", "-0", "-", - "http://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", //nolint:lll + "http://raw.githubusercontent.com/dotnet/install-scripts/5b142a1e445a6f060d6430b661408989e9580b85/src/dotnet-install.sh", }, }, expected: true, From ec36916c108c35ee5e80d5f26d143f722552a19f Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 5 Dec 2023 18:59:42 +0000 Subject: [PATCH 36/51] :seedling: convert Webhook check to probes (#3522) * :seedling: convert Webhook check to probes Signed-off-by: AdamKorcz * Add test + nits Signed-off-by: AdamKorcz * replace probe with OutcomeNotApplicable Signed-off-by: AdamKorcz * return one finding per webhook Signed-off-by: Adam Korczynski * change wording in def.yml Signed-off-by: Adam Korczynski * change wording in def.yml and checks.md Signed-off-by: Adam Korczynski * remove unused struct in test Signed-off-by: Adam Korczynski * align checks.md with checks.yaml Signed-off-by: Adam Korczynski * bring back experimental for webhooks Signed-off-by: Adam Korczynski * change 'token' to 'secret' in probe Signed-off-by: Adam Korczynski * use checker.MinResultScore instead of 0 Signed-off-by: Adam Korczynski * Change test name Signed-off-by: Adam Korczynski * use checker.MinResultScore instead of 0 Signed-off-by: Adam Korczynski * fix typo Signed-off-by: Adam Korczynski * Use checker.MaxResultScore instead of 10 Signed-off-by: Adam Korczynski * rename probe Signed-off-by: Adam Korczynski * remove the 'totalWebhooks' value from findings Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- checker/check_result_test.go | 8 + checks/evaluation/webhooks.go | 50 +++-- checks/evaluation/webhooks_test.go | 268 ++++++++++++++++--------- checks/webhook.go | 14 +- docs/checks.md | 2 +- docs/checks/internal/checks.yaml | 2 +- probes/entries.go | 4 + probes/webhooksUseSecrets/def.yml | 33 +++ probes/webhooksUseSecrets/impl.go | 78 +++++++ probes/webhooksUseSecrets/impl_test.go | 171 ++++++++++++++++ 10 files changed, 512 insertions(+), 118 deletions(-) create mode 100644 probes/webhooksUseSecrets/def.yml create mode 100644 probes/webhooksUseSecrets/impl.go create mode 100644 probes/webhooksUseSecrets/impl_test.go diff --git a/checker/check_result_test.go b/checker/check_result_test.go index cf792232704..2a6f93b5434 100644 --- a/checker/check_result_test.go +++ b/checker/check_result_test.go @@ -127,6 +127,14 @@ func TestCreateProportionalScore(t *testing.T) { }, want: 5, }, + { + name: "2 and 5", + args: args{ + success: 2, + total: 5, + }, + want: 4, + }, } for _, tt := range tests { tt := tt diff --git a/checks/evaluation/webhooks.go b/checks/evaluation/webhooks.go index d7a5a761923..37ed12c5e6b 100644 --- a/checks/evaluation/webhooks.go +++ b/checks/evaluation/webhooks.go @@ -20,42 +20,50 @@ import ( "github.com/ossf/scorecard/v4/checker" sce "github.com/ossf/scorecard/v4/errors" "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/webhooksUseSecrets" ) // Webhooks applies the score policy for the Webhooks check. -func Webhooks(name string, dl checker.DetailLogger, - r *checker.WebhooksData, +func Webhooks(name string, + findings []finding.Finding, dl checker.DetailLogger, ) checker.CheckResult { - if r == nil { - e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") + expectedProbes := []string{ + webhooksUseSecrets.Probe, + } + + if !finding.UniqueProbesEqual(findings, expectedProbes) { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results") return checker.CreateRuntimeErrorResult(name, e) } - if len(r.Webhooks) < 1 { - return checker.CreateMaxScoreResult(name, "no webhooks defined") + if len(findings) == 1 && findings[0].Outcome == finding.OutcomeNotApplicable { + return checker.CreateMaxScoreResult(name, "project does not have webhook") } - hasNoSecretCount := 0 - for _, hook := range r.Webhooks { - if !hook.UsesAuthSecret { - dl.Warn(&checker.LogMessage{ - Path: hook.Path, - Type: finding.FileTypeURL, - Text: "Webhook with no secret configured", - }) - hasNoSecretCount++ + var webhooksWithNoSecret int + + totalWebhooks := len(findings) + + for i := range findings { + f := &findings[i] + if f.Outcome == finding.OutcomeNegative { + webhooksWithNoSecret++ } } - if hasNoSecretCount == 0 { - return checker.CreateMaxScoreResult(name, fmt.Sprintf("all %d hook(s) have a secret configured", len(r.Webhooks))) + if totalWebhooks == webhooksWithNoSecret { + return checker.CreateMinScoreResult(name, "no hook(s) have a secret configured") } - if len(r.Webhooks) == hasNoSecretCount { - return checker.CreateMinScoreResult(name, fmt.Sprintf("%d hook(s) do not have a secret configured", len(r.Webhooks))) + if webhooksWithNoSecret == 0 { + msg := fmt.Sprintf("All %d of the projects webhooks are configured with a secret", totalWebhooks) + return checker.CreateMaxScoreResult(name, msg) } + msg := fmt.Sprintf("%d out of the projects %d webhooks are configured without a secret", + webhooksWithNoSecret, + totalWebhooks) + return checker.CreateProportionalScoreResult(name, - fmt.Sprintf("%d/%d hook(s) with no secrets configured detected", - hasNoSecretCount, len(r.Webhooks)), hasNoSecretCount, len(r.Webhooks)) + msg, totalWebhooks-webhooksWithNoSecret, totalWebhooks) } diff --git a/checks/evaluation/webhooks_test.go b/checks/evaluation/webhooks_test.go index 4a34f900f4e..a698e732115 100644 --- a/checks/evaluation/webhooks_test.go +++ b/checks/evaluation/webhooks_test.go @@ -18,135 +18,219 @@ import ( "testing" "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" scut "github.com/ossf/scorecard/v4/utests" ) // TestWebhooks tests the webhooks check. func TestWebhooks(t *testing.T) { t.Parallel() - //nolint:govet - type args struct { - name string - dl checker.DetailLogger - r *checker.WebhooksData - } tests := []struct { - name string - args args - want checker.CheckResult - wantErr bool + name string + findings []finding.Finding + result scut.TestReturn }{ { - name: "r nil", - args: args{ - name: "test_webhook_check_pass", - dl: &scut.TestDetailLogger{}, + name: "no webhooks", + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNotApplicable, + }, + }, + result: scut.TestReturn{ + Score: checker.MaxResultScore, }, - wantErr: true, }, { - name: "no webhooks", - args: args{ - name: "no webhooks", - dl: &scut.TestDetailLogger{}, - r: &checker.WebhooksData{}, + name: "1 webhook with no secret", + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, }, - want: checker.CheckResult{ - Score: checker.MaxResultScore, + result: scut.TestReturn{ + Score: checker.MinResultScore, }, }, { name: "1 webhook with secret", - args: args{ - name: "1 webhook with secret", - dl: &scut.TestDetailLogger{}, - r: &checker.WebhooksData{ - Webhooks: []clients.Webhook{ - { - Path: "https://github.com/owner/repo/settings/hooks/1234", - ID: 1234, - UsesAuthSecret: true, - }, - }, + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, }, }, - want: checker.CheckResult{ - Score: 10, + result: scut.TestReturn{ + Score: checker.MaxResultScore, }, }, { - name: "1 webhook with no secret", - args: args{ - name: "1 webhook with no secret", - dl: &scut.TestDetailLogger{}, - r: &checker.WebhooksData{ - Webhooks: []clients.Webhook{ - { - Path: "https://github.com/owner/repo/settings/hooks/1234", - ID: 1234, - UsesAuthSecret: false, - }, - }, + name: "2 webhooks one of which has secret", + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, }, }, - want: checker.CheckResult{ - Score: 0, + result: scut.TestReturn{ + Score: 5, }, }, { - name: "many webhooks with no secret and with secret", - args: args{ - name: "many webhooks with no secret and with secret", - dl: &scut.TestDetailLogger{}, - r: &checker.WebhooksData{ - Webhooks: []clients.Webhook{ - { - Path: "https://github.com/owner/repo/settings/hooks/1234", - ID: 1234, - UsesAuthSecret: false, - }, - { - Path: "https://github.com/owner/repo/settings/hooks/1111", - ID: 1111, - UsesAuthSecret: true, - }, - { - Path: "https://github.com/owner/repo/settings/hooks/4444", - ID: 4444, - UsesAuthSecret: true, - }, - { - Path: "https://github.com/owner/repo/settings/hooks/3333", - ID: 3333, - UsesAuthSecret: false, - }, - { - Path: "https://github.com/owner/repo/settings/hooks/2222", - ID: 2222, - UsesAuthSecret: false, - }, - }, + name: "Five webhooks three of which have secrets", + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, }, }, - want: checker.CheckResult{ + result: scut.TestReturn{ Score: 6, }, }, + { + name: "One of 12 webhooks does not have secrets", + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomePositive, + }, + }, + result: scut.TestReturn{ + Score: 9, + }, + }, + { + name: "Score should not drop below min score", + findings: []finding.Finding{ + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + { + Probe: "webhooksUseSecrets", + Outcome: finding.OutcomeNegative, + }, + }, + result: scut.TestReturn{ + Score: checker.MinResultScore, + }, + }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - got := Webhooks(tt.args.name, tt.args.dl, tt.args.r) - if tt.wantErr { - if got.Error == nil { - t.Errorf("Webhooks() error = %v, wantErr %v", got.Error, tt.wantErr) - } - } else { - if got.Score != tt.want.Score { - t.Errorf("Webhooks() = %v, want %v", got.Score, tt.want.Score) - } + dl := scut.TestDetailLogger{} + got := Webhooks(tt.name, tt.findings, &dl) + if !scut.ValidateTestReturn(t, tt.name, &tt.result, &got, &dl) { + t.Errorf("got %v, expected %v", got, tt.result) } }) } diff --git a/checks/webhook.go b/checks/webhook.go index 7a571aaced4..cc3284560f7 100644 --- a/checks/webhook.go +++ b/checks/webhook.go @@ -21,6 +21,8 @@ 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" + "github.com/ossf/scorecard/v4/probes/zrunner" ) const ( @@ -56,10 +58,16 @@ func WebHooks(c *checker.CheckRequest) checker.CheckResult { } // Set the raw results. - if c.RawResults != nil { - c.RawResults.WebhookResults = rawData + pRawResults := getRawResults(c) + pRawResults.WebhookResults = rawData + + // Evaluate the probes. + findings, err := zrunner.Run(pRawResults, probes.Webhook) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckWebHooks, e) } // Return the score evaluation. - return evaluation.Webhooks(CheckWebHooks, c.Dlogger, &rawData) + return evaluation.Webhooks(CheckWebHooks, findings, c.Dlogger) } diff --git a/docs/checks.md b/docs/checks.md index 9a8fa379866..8d049df23ed 100644 --- a/docs/checks.md +++ b/docs/checks.md @@ -678,7 +678,7 @@ This check determines whether the webhook defined in the repository has a token **Remediation steps** -- Check whether your service supports token authentication. +- Check if the service your webhooks is configured with supports secrets. - If there is support for token authentication, set the secret in the webhook configuration. See [Setting up a webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#setting-up-a-webhook). - If there is no support for token authentication, request the webhook service implement token authentication functionality by following [these directions](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). diff --git a/docs/checks/internal/checks.yaml b/docs/checks/internal/checks.yaml index 2ec49840581..7dabefcc5e8 100644 --- a/docs/checks/internal/checks.yaml +++ b/docs/checks/internal/checks.yaml @@ -826,7 +826,7 @@ checks: This check determines whether the webhook defined in the repository has a token configured to authenticate the origins of requests. remediation: - >- - Check whether your service supports token authentication. + Check if the service your webhooks is configured with supports secrets. - >- If there is support for token authentication, set the secret in the webhook configuration. See [Setting up a webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#setting-up-a-webhook). - >- diff --git a/probes/entries.go b/probes/entries.go index c9d125f81e5..4486ecd8913 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -53,6 +53,7 @@ import ( "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/webhooksUseSecrets" ) // ProbeImpl is the implementation of a probe. @@ -125,6 +126,9 @@ var ( BinaryArtifacts = []ProbeImpl{ freeOfUnverifiedBinaryArtifacts.Run, } + Webhook = []ProbeImpl{ + webhooksUseSecrets.Run, + } ) //nolint:gochecknoinits diff --git a/probes/webhooksUseSecrets/def.yml b/probes/webhooksUseSecrets/def.yml new file mode 100644 index 00000000000..d7b81894568 --- /dev/null +++ b/probes/webhooksUseSecrets/def.yml @@ -0,0 +1,33 @@ +# 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: webhooksUseSecrets +short: This check determines whether the webhooks defined in the repository have secrets configured to authenticate the origins of requests. +motivation: > + Webhooks without secret authorization have the potential to make projects accessible to third-parties. +implementation: > + The probe checks all webhooks of a project and checks whether each uses secret authentication. +outcome: + - If the project has any webhooks without secret authorization, the probe returns as many OutcomeNegative (0) as the project has webhooks without secret authorization and as many OutcomePositive as there are webhooks with secret authorization. All findings include the path to the webhook. + - If the project does not have any webhooks without secret authorization, the probe returns one OutcomePositive (1). +remediation: + effort: Low + text: + - Check if the service your webhooks is configured with supports secrets. + - If there is support for secret authentication, set the secret in the webhook configuration. See [Setting up a webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#setting-up-a-webhook). + - If there is no support for secret authentication, request the webhook service implement secret authentication functionality by following [these directions](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). + markdown: + - Check if the service your webhooks is configured with supports secrets. + - If there is support for secret authentication, set the secret in the webhook configuration. See [Setting up a webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#setting-up-a-webhook). + - If there is no support for secret authentication, request the webhook service implement secret authentication functionality by following [these directions](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). \ No newline at end of file diff --git a/probes/webhooksUseSecrets/impl.go b/probes/webhooksUseSecrets/impl.go new file mode 100644 index 00000000000..08f87b14000 --- /dev/null +++ b/probes/webhooksUseSecrets/impl.go @@ -0,0 +1,78 @@ +// 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. + +//nolint:stylecheck +package webhooksUseSecrets + +import ( + "embed" + "fmt" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const Probe = "webhooksUseSecrets" + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + r := raw.WebhookResults + var findings []finding.Finding + + if len(r.Webhooks) == 0 { + f, err := finding.NewWith(fs, Probe, + "Repository does not have webhooks.", nil, + finding.OutcomeNotApplicable) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + return findings, Probe, nil + } + + for _, hook := range r.Webhooks { + if hook.UsesAuthSecret { + msg := "Webhook with token authorization found." + f, err := finding.NewWith(fs, Probe, + msg, nil, finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithLocation(&finding.Location{ + Path: hook.Path, + }) + findings = append(findings, *f) + } else { + msg := "Webhook without token authorization found." + f, err := finding.NewWith(fs, Probe, + msg, nil, finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f = f.WithLocation(&finding.Location{ + Path: hook.Path, + }) + findings = append(findings, *f) + } + } + + return findings, Probe, nil +} diff --git a/probes/webhooksUseSecrets/impl_test.go b/probes/webhooksUseSecrets/impl_test.go new file mode 100644 index 00000000000..eaf073d1f35 --- /dev/null +++ b/probes/webhooksUseSecrets/impl_test.go @@ -0,0 +1,171 @@ +// 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. + +//nolint:stylecheck +package webhooksUseSecrets + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "No Webhooks", + raw: &checker.RawResults{ + WebhookResults: checker.WebhooksData{ + Webhooks: []clients.Webhook{}, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNotApplicable, + }, + }, + { + name: "Webhooks present with auth secret", + raw: &checker.RawResults{ + WebhookResults: checker.WebhooksData{ + Webhooks: []clients.Webhook{ + { + Path: "https://github.com/owner/repo/settings/hooks/1234", + ID: 1, + UsesAuthSecret: true, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Webhooks present without auth secret", + raw: &checker.RawResults{ + WebhookResults: checker.WebhooksData{ + Webhooks: []clients.Webhook{ + { + Path: "https://github.com/owner/repo/settings/hooks/1234", + ID: 1, + UsesAuthSecret: false, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + }, + }, + { + name: "Multiple webhooks present, one without auth secret", + raw: &checker.RawResults{ + WebhookResults: checker.WebhooksData{ + Webhooks: []clients.Webhook{ + { + Path: "https://github.com/owner/repo/settings/hooks/1234", + ID: 1, + UsesAuthSecret: false, + }, + { + Path: "https://github.com/owner/repo/settings/hooks/12345", + ID: 2, + UsesAuthSecret: true, + }, + { + Path: "https://github.com/owner/repo/settings/hooks/12346", + ID: 3, + UsesAuthSecret: true, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, finding.OutcomePositive, finding.OutcomePositive, + }, + }, + { + name: "Multiple webhooks present, two without auth secret", + raw: &checker.RawResults{ + WebhookResults: checker.WebhooksData{ + Webhooks: []clients.Webhook{ + { + Path: "https://github.com/owner/repo/settings/hooks/1234", + ID: 1, + UsesAuthSecret: false, + }, + { + Path: "https://github.com/owner/repo/settings/hooks/12345", + ID: 2, + UsesAuthSecret: true, + }, + { + Path: "https://github.com/owner/repo/settings/hooks/12346", + ID: 3, + UsesAuthSecret: true, + }, + { + Path: "https://github.com/owner/repo/settings/hooks/12346", + ID: 4, + UsesAuthSecret: false, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, finding.OutcomePositive, + finding.OutcomePositive, finding.OutcomeNegative, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} From 320ce05868940a2d54ab439d1e8c2728d7729649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:25:19 +0000 Subject: [PATCH 37/51] :seedling: Bump the github-actions group with 3 updates (#3715) Bumps the github-actions group with 3 updates: [actions/dependency-review-action](https://github.com/actions/dependency-review-action), [tj-actions/changed-files](https://github.com/tj-actions/changed-files) and [kubernetes-sigs/kubebuilder-release-tools](https://github.com/kubernetes-sigs/kubebuilder-release-tools). Updates `actions/dependency-review-action` from 3.1.3 to 3.1.4 - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/7bbfa034e752445ea40215fff1c3bf9597993d3f...01bc87099ba56df1e897b6874784491ea6309bc4) Updates `tj-actions/changed-files` from 40.1.1 to 40.2.1 - [Release notes](https://github.com/tj-actions/changed-files/releases) - [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md) - [Commits](https://github.com/tj-actions/changed-files/compare/25ef3926d147cd02fc7e931c1ef50772bbb0d25d...1c938490c880156b746568a518594309cfb3f66b) Updates `kubernetes-sigs/kubebuilder-release-tools` from 0.4.2 to 0.4.3 - [Release notes](https://github.com/kubernetes-sigs/kubebuilder-release-tools/releases) - [Changelog](https://github.com/kubernetes-sigs/kubebuilder-release-tools/blob/master/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/kubebuilder-release-tools/compare/3c3411345eedc489d1022288aa844691e92a9c29...012269a88fa4c034a0acf1ba84c26b195c0dbab4) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: tj-actions/changed-files dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: kubernetes-sigs/kubebuilder-release-tools dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/depsreview.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/verify.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/depsreview.yml b/.github/workflows/depsreview.yml index e60f76647b0..adfaa7bc7b8 100644 --- a/.github/workflows/depsreview.yml +++ b/.github/workflows/depsreview.yml @@ -24,4 +24,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: 'Dependency Review' - uses: actions/dependency-review-action@7bbfa034e752445ea40215fff1c3bf9597993d3f # v3.1.3 + uses: actions/dependency-review-action@01bc87099ba56df1e897b6874784491ea6309bc4 # v3.1.4 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7fea70efaa7..8940d178bae 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -40,7 +40,7 @@ jobs: fetch-depth: 2 # needed to diff changed files - id: files name: Get changed files - uses: tj-actions/changed-files@25ef3926d147cd02fc7e931c1ef50772bbb0d25d #v40.1.1 + uses: tj-actions/changed-files@1c938490c880156b746568a518594309cfb3f66b #v40.2.1 with: files_ignore: '**.md' - id: docs_only_check diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 78bc7d0b1e1..e6024834fdd 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -32,6 +32,6 @@ jobs: - name: Verifier action id: verifier - uses: kubernetes-sigs/kubebuilder-release-tools@3c3411345eedc489d1022288aa844691e92a9c29 # v0.4.2 + uses: kubernetes-sigs/kubebuilder-release-tools@012269a88fa4c034a0acf1ba84c26b195c0dbab4 # v0.4.3 with: github_token: ${{ secrets.GITHUB_TOKEN }} From 6ea9c8d2a2a30a25c30cca4321d32ac957283106 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Wed, 6 Dec 2023 00:08:19 +0000 Subject: [PATCH 38/51] :seedling: Pinned dependencies: create findings from processing errors (#3711) * :seedling: refactor pinned dependencies Signed-off-by: AdamKorcz * remove remediation from test Signed-off-by: AdamKorcz * :seedling: create findings from processing errors Signed-off-by: Adam Korczynski * correct style of loop Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- checks/evaluation/pinned_dependencies.go | 41 +++++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/checks/evaluation/pinned_dependencies.go b/checks/evaluation/pinned_dependencies.go index 762a4359073..5583c846054 100644 --- a/checks/evaluation/pinned_dependencies.go +++ b/checks/evaluation/pinned_dependencies.go @@ -92,10 +92,21 @@ func probeRemToRuleRem(rem *probe.Remediation) *rule.Remediation { } } -func dependenciesToFindings(deps []checker.Dependency) ([]finding.Finding, error) { +func dependenciesToFindings(r *checker.PinningDependenciesData) ([]finding.Finding, error) { findings := make([]finding.Finding, 0) - for i := range deps { - rr := deps[i] + + 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") @@ -199,24 +210,15 @@ func PinningDependencies(name string, c *checker.CheckRequest, pr := make(map[checker.DependencyUseType]pinnedResult) dl := c.Dlogger - for _, e := range r.ProcessingErrors { - e := e - dl.Info(&checker.LogMessage{ - Finding: &finding.Finding{ - Message: generateTextIncompleteResults(e), - Location: &e.Location, - }, - }) - } - - findings, err := dependenciesToFindings(r.Dependencies) + findings, err := dependenciesToFindings(r) if err != nil { return checker.CreateRuntimeErrorResult(name, err) } for i := range findings { f := findings[i] - if f.Outcome == finding.OutcomeNotApplicable { + switch f.Outcome { + case finding.OutcomeNotApplicable: if f.Location != nil { dl.Debug(&checker.LogMessage{ Path: f.Location.Path, @@ -232,7 +234,7 @@ func PinningDependencies(name string, c *checker.CheckRequest, }) } continue - } else if f.Outcome == finding.OutcomeNegative { + case finding.OutcomeNegative: lm := &checker.LogMessage{ Path: f.Location.Path, Type: f.Location.Type, @@ -246,6 +248,13 @@ func PinningDependencies(name string, c *checker.CheckRequest, lm.Remediation = probeRemToRuleRem(f.Remediation) } dl.Warn(lm) + case finding.OutcomeNotAvailable: + dl.Info(&checker.LogMessage{ + Finding: &f, + }) + continue + default: + // ignore } updatePinningResults(intToDepType[f.Values["dependencyType"]], f.Outcome, f.Location.Snippet, From 5dc03b72e109d67afe4c91a0fbe52a3c1678a97f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:52:09 -0800 Subject: [PATCH 39/51] :seedling: Bump github.com/google/osv-scanner from 1.4.3 to 1.5.0 (#3716) Bumps [github.com/google/osv-scanner](https://github.com/google/osv-scanner) from 1.4.3 to 1.5.0. - [Release notes](https://github.com/google/osv-scanner/releases) - [Changelog](https://github.com/google/osv-scanner/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/osv-scanner/compare/v1.4.3...v1.5.0) --- updated-dependencies: - dependency-name: github.com/google/osv-scanner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 6637d9ecbe7..a1fe32e529a 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( go.opencensus.io v0.24.0 gocloud.dev v0.34.0 golang.org/x/text v0.14.0 - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 @@ -43,7 +43,7 @@ require ( github.com/caarlos0/env/v6 v6.10.0 github.com/gobwas/glob v0.2.3 github.com/google/go-github/v53 v53.2.0 - github.com/google/osv-scanner v1.4.3 + github.com/google/osv-scanner v1.5.0 github.com/mcuadros/go-jsonschema-generator v0.0.0-20200330054847-ba7a369d4303 github.com/onsi/ginkgo/v2 v2.13.2 github.com/otiai10/copy v1.14.0 @@ -55,6 +55,7 @@ require ( cloud.google.com/go/containeranalysis v0.11.1 // indirect cloud.google.com/go/kms v1.15.3 // indirect dario.cat/mergo v1.0.0 // indirect + deps.dev/api/v3alpha v0.0.0-20231114023923-e40c4d5c34e5 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/CycloneDX/cyclonedx-go v0.7.2 // indirect github.com/anchore/go-struct-converter v0.0.0-20230627203149-c72ef8859ca9 // indirect @@ -70,8 +71,6 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/goark/errs v1.3.2 // indirect - github.com/goark/go-cvss v1.6.6 // indirect github.com/goccy/go-json v0.9.11 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -97,6 +96,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/owenrumney/go-sarif/v2 v2.3.0 // indirect github.com/package-url/packageurl-go v0.1.2 // indirect + github.com/pandatix/go-cvss v0.6.2 // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/prometheus/prometheus v0.46.0 // indirect @@ -105,7 +105,7 @@ require ( github.com/spdx/gordf v0.0.0-20221230105357-b735bd5aac89 // indirect github.com/spdx/tools-golang v0.5.3 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - golang.org/x/mod v0.13.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/vuln v1.0.1 // indirect @@ -173,10 +173,10 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect golang.org/x/crypto v0.16.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.15.0 - golang.org/x/sync v0.4.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.149.0 // indirect diff --git a/go.sum b/go.sum index 3353fbf9861..272d73498ce 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.14 h1:zBakwHardp9Jcb8sQHcHpX contrib.go.opencensus.io/exporter/stackdriver v0.13.14/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +deps.dev/api/v3alpha v0.0.0-20231114023923-e40c4d5c34e5 h1:Vvh14FIzt0+LaLWn2l09FKQbdXBVxIjtPbjFiykXYlI= +deps.dev/api/v3alpha v0.0.0-20231114023923-e40c4d5c34e5/go.mod h1:uRN72FJn1F0FD/2ZYUOqdyFMu8VUsyHxvmZAMW30/DA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -321,10 +323,6 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/goark/errs v1.3.2 h1:ifccNe1aK7Xezt4XVYwHUqalmnfhuphnEvh3FshCReQ= -github.com/goark/errs v1.3.2/go.mod h1:ZsQucxaDFVfSB8I99j4bxkDRfNOrlKINwg72QMuRWKw= -github.com/goark/go-cvss v1.6.6 h1:WJFuIWqmAw1Ilb9USv0vuX+nYzOWJp8lIujseJ/y3sU= -github.com/goark/go-cvss v1.6.6/go.mod h1:H3qbfUSUlV7XtA3EwWNunvXz6OySwWHOuO+R6ZPMQPI= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= @@ -415,8 +413,8 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/osv-scanner v1.4.3 h1:V+vIjrC+HsDSzq8vWok/prjXl3Xg6i8u7gpejEIkcME= -github.com/google/osv-scanner v1.4.3/go.mod h1:e2jwYUxCBQxlXlcMP7FdlmNu5XlBKA4hEhVXDBZZSzA= +github.com/google/osv-scanner v1.5.0 h1:ln0i1o4fEu3iPlAIeSJg3zRxBEJjO+IvKDBMX/R6He0= +github.com/google/osv-scanner v1.5.0/go.mod h1:+BqMim8RGiZzPiXubV/UTvxQCJPxt1yCgZegn74oh8A= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -648,6 +646,8 @@ github.com/owenrumney/go-sarif/v2 v2.3.0 h1:wP5yEpI53zr0v5cBmagXzLbHZp9Oylyo3AJD github.com/owenrumney/go-sarif/v2 v2.3.0/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= github.com/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4= github.com/package-url/packageurl-go v0.1.2/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= +github.com/pandatix/go-cvss v0.6.2 h1:TFiHlzUkT67s6UkelHmK6s1INKVUG7nlKYiWWDTITGI= +github.com/pandatix/go-cvss v0.6.2/go.mod h1:jDXYlQBZrc8nvrMUVVvTG8PhmuShOnKrxP53nOFkt8Q= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -846,8 +846,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -871,8 +871,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -939,8 +939,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1077,8 +1077,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/vuln v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU= golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 30ef6b10268b645008b9360c32fe1829752db99d Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Mon, 11 Dec 2023 18:15:50 +0000 Subject: [PATCH 40/51] :seedling: convert CI-Tests check to probes (#3621) * :seedling: convert CITest check to probes Signed-off-by: AdamKorcz * fix lint issues Signed-off-by: Adam Korczynski * debug failing integration test Signed-off-by: Adam Korczynski * Add negative outcome to test Signed-off-by: Adam Korczynski * remove 'totalTested' and 'totalMerged' values from findings Signed-off-by: Adam Korczynski * Log at debug level Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- checks/ci_tests.go | 18 +- checks/evaluation/ci_tests.go | 134 +++----- checks/evaluation/ci_tests_test.go | 470 ++++------------------------ probes/entries.go | 4 + probes/testsRunInCI/def.yml | 28 ++ probes/testsRunInCI/impl.go | 169 ++++++++++ probes/testsRunInCI/impl_test.go | 486 +++++++++++++++++++++++++++++ 7 files changed, 806 insertions(+), 503 deletions(-) create mode 100644 probes/testsRunInCI/def.yml create mode 100644 probes/testsRunInCI/impl.go create mode 100644 probes/testsRunInCI/impl_test.go diff --git a/checks/ci_tests.go b/checks/ci_tests.go index c2e577385af..b5d37405710 100644 --- a/checks/ci_tests.go +++ b/checks/ci_tests.go @@ -19,9 +19,10 @@ 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" + "github.com/ossf/scorecard/v4/probes/zrunner" ) -// CheckCodeReview is the registered name for DoesCodeReview. const CheckCITests = "CI-Tests" //nolint:gochecknoinits @@ -35,7 +36,6 @@ func init() { } } -// CodeReview will check if the maintainers perform code review. func CITests(c *checker.CheckRequest) checker.CheckResult { rawData, err := raw.CITests(c.RepoClient) if err != nil { @@ -43,11 +43,15 @@ func CITests(c *checker.CheckRequest) checker.CheckResult { return checker.CreateRuntimeErrorResult(CheckCITests, e) } - // Return raw results. - if c.RawResults != nil { - c.RawResults.CITestResults = rawData + pRawResults := getRawResults(c) + pRawResults.CITestResults = rawData + + // Evaluate the probes. + findings, err := zrunner.Run(pRawResults, probes.CITests) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckCITests, e) } - // Return the score evaluation. - return evaluation.CITests(CheckCITests, &rawData, c.Dlogger) + return evaluation.CITests(CheckCITests, findings, c.Dlogger) } diff --git a/checks/evaluation/ci_tests.go b/checks/evaluation/ci_tests.go index 8dc9311abe6..4c55fcc31c9 100644 --- a/checks/evaluation/ci_tests.go +++ b/checks/evaluation/ci_tests.go @@ -16,122 +16,72 @@ package evaluation import ( "fmt" - "strings" "github.com/ossf/scorecard/v4/checker" + sce "github.com/ossf/scorecard/v4/errors" "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/testsRunInCI" ) -const ( - // CheckCITests is the registered name for CITests. - CheckCITests = "CI-Tests" - success = "success" -) - -func CITests(_ string, c *checker.CITestData, dl checker.DetailLogger) checker.CheckResult { - totalMerged := 0 - totalTested := 0 - for i := range c.CIInfo { - r := c.CIInfo[i] - totalMerged++ - - var foundCI bool - - // GitHub Statuses. - prSuccessStatus, err := prHasSuccessStatus(r, dl) - if err != nil { - return checker.CreateRuntimeErrorResult(CheckCITests, err) - } - if prSuccessStatus { - totalTested++ - foundCI = true - continue - } +const CheckCITests = "CI-Tests" - // GitHub Check Runs. - prCheckSuccessful, err := prHasSuccessfulCheck(r, dl) - if err != nil { - return checker.CreateRuntimeErrorResult(CheckCITests, err) - } - if prCheckSuccessful { - totalTested++ - foundCI = true - } - - if !foundCI { - // Log message says commit, but really we only care about PRs, and - // use only one commit (branch HEAD) to refer to all commits in a PR +func CITests(name string, + findings []finding.Finding, + dl checker.DetailLogger, +) checker.CheckResult { + expectedProbes := []string{ + testsRunInCI.Probe, + } + if !finding.UniqueProbesEqual(findings, expectedProbes) { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results") + return checker.CreateRuntimeErrorResult(name, e) + } + // Debug PRs that were merged without CI tests + for i := range findings { + f := &findings[i] + if f.Outcome == finding.OutcomeNegative || f.Outcome == finding.OutcomePositive { dl.Debug(&checker.LogMessage{ - Text: fmt.Sprintf("merged PR %d without CI test at HEAD: %s", r.PullRequestNumber, r.HeadSHA), + Text: f.Message, }) } } - if totalMerged == 0 { + // check that the project has pull requests + if noPullRequestsFound(findings) { return checker.CreateInconclusiveResult(CheckCITests, "no pull request found") } + totalMerged, totalTested := getMergedAndTested(findings) + + if totalMerged < totalTested || len(findings) < totalTested { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid finding values") + return checker.CreateRuntimeErrorResult(name, e) + } + reason := fmt.Sprintf("%d out of %d merged PRs checked by a CI test", totalTested, totalMerged) return checker.CreateProportionalScoreResult(CheckCITests, reason, totalTested, totalMerged) } -// PR has a status marked 'success' and a CI-related context. -// -//nolint:unparam -func prHasSuccessStatus(r checker.RevisionCIInfo, dl checker.DetailLogger) (bool, error) { - for _, status := range r.Statuses { - if status.State != success { - continue - } - if isTest(status.Context) || isTest(status.TargetURL) { - dl.Debug(&checker.LogMessage{ - Path: status.URL, - Type: finding.FileTypeURL, - Text: fmt.Sprintf("CI test found: pr: %s, context: %s", r.HeadSHA, - status.Context), - }) - return true, nil - } - } - return false, nil -} +func getMergedAndTested(findings []finding.Finding) (int, int) { + totalMerged := 0 + totalTested := 0 -// PR has a successful CI-related check. -// -//nolint:unparam -func prHasSuccessfulCheck(r checker.RevisionCIInfo, dl checker.DetailLogger) (bool, error) { - for _, cr := range r.CheckRuns { - if cr.Status != "completed" { - continue - } - if cr.Conclusion != success { - continue - } - if isTest(cr.App.Slug) { - dl.Debug(&checker.LogMessage{ - Path: cr.URL, - Type: finding.FileTypeURL, - Text: fmt.Sprintf("CI test found: pr: %d, context: %s", r.PullRequestNumber, - cr.App.Slug), - }) - return true, nil + for i := range findings { + f := &findings[i] + totalMerged++ + if f.Outcome == finding.OutcomePositive { + totalTested++ } } - return false, nil -} -// isTest returns true if the given string is a CI test. -func isTest(s string) bool { - l := strings.ToLower(s) + return totalMerged, totalTested +} - // Add more patterns here! - for _, pattern := range []string{ - "appveyor", "buildkite", "circleci", "e2e", "github-actions", "jenkins", - "mergeable", "packit-as-a-service", "semaphoreci", "test", "travis-ci", - "flutter-dashboard", "Cirrus CI", "azure-pipelines", - } { - if strings.Contains(l, pattern) { +func noPullRequestsFound(findings []finding.Finding) bool { + for i := range findings { + f := &findings[i] + if f.Outcome == finding.OutcomeNotApplicable { return true } } diff --git a/checks/evaluation/ci_tests_test.go b/checks/evaluation/ci_tests_test.go index 19e20d3668c..825ad5c6142 100644 --- a/checks/evaluation/ci_tests_test.go +++ b/checks/evaluation/ci_tests_test.go @@ -16,441 +16,103 @@ package evaluation import ( "testing" - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" scut "github.com/ossf/scorecard/v4/utests" ) -func Test_isTest(t *testing.T) { - t.Parallel() - type args struct { - s string - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "appveyor", - args: args{ - s: "appveyor", - }, - want: true, - }, - { - name: "circleci", - args: args{ - s: "circleci", - }, - want: true, - }, - { - name: "jenkins", - args: args{ - s: "jenkins", - }, - want: true, - }, - { - name: "e2e", - args: args{ - s: "e2e", - }, - want: true, - }, - { - name: "github-actions", - args: args{ - s: "github-actions", - }, - want: true, - }, - { - name: "mergeable", - args: args{ - s: "mergeable", - }, - want: true, - }, - { - name: "packit-as-a-service", - args: args{ - s: "packit-as-a-service", - }, - want: true, - }, - { - name: "semaphoreci", - args: args{ - s: "semaphoreci", - }, - want: true, - }, - { - name: "test", - args: args{ - s: "test", - }, - want: true, - }, - { - name: "travis-ci", - args: args{ - s: "travis-ci", - }, - want: true, - }, - { - name: "azure-pipelines", - args: args{ - s: "azure-pipelines", - }, - want: true, - }, - { - name: "non-existing", - args: args{ - s: "non-existing", - }, - want: false, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - if got := isTest(tt.args.s); got != tt.want { - t.Errorf("isTest() = %v, want %v for test %v", got, tt.want, tt.name) - } - }) - } -} - -func Test_prHasSuccessfulCheck(t *testing.T) { +// Tip: If you add new findings to this test, else +// add a unit test to the probes with the same findings. +func TestCITests(t *testing.T) { t.Parallel() - tests := []struct { - name string - args checker.RevisionCIInfo - want bool - wantErr bool + name string + findings []finding.Finding + result scut.TestReturn }{ { - name: "check run with conclusion success", - args: checker.RevisionCIInfo{ - PullRequestNumber: 1, - HeadSHA: "sha", - CheckRuns: []clients.CheckRun{ - { - App: clients.CheckRunApp{Slug: "test"}, - Conclusion: "success", - URL: "url", - Status: "completed", - }, + name: "Has CI tests. 1 tested out of 1 merged", + findings: []finding.Finding{ + { + Outcome: finding.OutcomePositive, + Probe: "testsRunInCI", + Message: "CI test found: pr: 1, context: e2e", + Location: &finding.Location{Type: 4}, }, }, - want: true, - wantErr: false, - }, - { - name: "check run with conclusion not success", - args: checker.RevisionCIInfo{ - PullRequestNumber: 1, - HeadSHA: "sha", - CheckRuns: []clients.CheckRun{ - { - App: clients.CheckRunApp{Slug: "test"}, - Conclusion: "failed", - URL: "url", - Status: "completed", - }, - }, + result: scut.TestReturn{ + Score: 10, + NumberOfDebug: 1, }, - want: false, - wantErr: false, }, { - name: "check run with conclusion not success", - args: checker.RevisionCIInfo{ - PullRequestNumber: 1, - HeadSHA: "sha", - CheckRuns: []clients.CheckRun{ - { - App: clients.CheckRunApp{Slug: "test"}, - Conclusion: "success", - URL: "url", - Status: "notcompleted", - }, + name: "Has CI tests. 3 tested out of 4 merged", + findings: []finding.Finding{ + { + Outcome: finding.OutcomePositive, + Probe: "testsRunInCI", + Message: "CI test found: pr: 1, context: e2e", + Location: &finding.Location{Type: 4}, }, - }, - want: false, - wantErr: false, - }, - } - for _, tt := range tests { - tt := tt - dl := &scut.TestDetailLogger{} - - got, err := prHasSuccessfulCheck(tt.args, dl) - if err != nil { - t.Fatalf("unexpected err: %v", err) - } - if got != tt.want { - t.Errorf("prHasSuccessfulCheck() = %v, want %v", got, tt.want) - } - } -} - -func Test_prHasSuccessStatus(t *testing.T) { - t.Parallel() - type args struct { //nolint:govet - r checker.RevisionCIInfo - dl checker.DetailLogger - } - tests := []struct { //nolint:govet - name string - args args - want bool - wantErr bool - }{ - { - name: "empty revision", - args: args{ - r: checker.RevisionCIInfo{}, - }, - want: false, - wantErr: false, - }, - { - name: "no statuses", - args: args{ - r: checker.RevisionCIInfo{ - Statuses: []clients.Status{}, - }, - }, - }, - { - name: "status is not success", - args: args{ - r: checker.RevisionCIInfo{ - Statuses: []clients.Status{ - { - State: "failure", - }, - }, - }, - }, - }, - { - name: "status is success", - args: args{ - r: checker.RevisionCIInfo{ - Statuses: []clients.Status{ - { - State: "success", - Context: CheckCITests, - }, - }, + { + Outcome: finding.OutcomePositive, + Probe: "testsRunInCI", + Message: "CI test found: pr: 1, context: e2e", + Location: &finding.Location{Type: 4}, }, - dl: &scut.TestDetailLogger{}, - }, - want: true, - wantErr: false, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - got, err := prHasSuccessStatus(tt.args.r, tt.args.dl) - if (err != nil) != tt.wantErr { - t.Errorf("prHasSuccessStatus() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("prHasSuccessStatus() got = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_prHasSuccessfulCheckAdditional(t *testing.T) { - t.Parallel() - type args struct { //nolint:govet - r checker.RevisionCIInfo - dl checker.DetailLogger - } - tests := []struct { //nolint:govet - name string - args args - want bool - wantErr bool - }{ - { - name: "empty revision", - args: args{ - r: checker.RevisionCIInfo{}, - }, - want: false, - wantErr: false, - }, - { - name: "status is not completed", - args: args{ - r: checker.RevisionCIInfo{ - CheckRuns: []clients.CheckRun{ - { - Status: "notcompleted", - }, - }, + { + Outcome: finding.OutcomePositive, + Probe: "testsRunInCI", + Message: "CI test found: pr: 1, context: e2e", + Location: &finding.Location{Type: 4}, }, - }, - }, - { - name: "status is not success", - args: args{ - r: checker.RevisionCIInfo{ - CheckRuns: []clients.CheckRun{ - { - Status: "completed", - Conclusion: "failure", - }, - }, + { + Outcome: finding.OutcomeNegative, + Probe: "testsRunInCI", + Message: "CI test found: pr: 1, context: e2e", + Location: &finding.Location{Type: 4}, }, }, - }, - { - name: "conclusion is success", - args: args{ - r: checker.RevisionCIInfo{ - CheckRuns: []clients.CheckRun{ - { - Status: "completed", - Conclusion: "success", - }, - }, - }, + result: scut.TestReturn{ + Score: 7, + NumberOfDebug: 4, }, }, { - name: "conclusion is succesls with a valid app slug", - args: args{ - r: checker.RevisionCIInfo{ - CheckRuns: []clients.CheckRun{ - { - Status: "completed", - Conclusion: "success", - App: clients.CheckRunApp{Slug: "e2e"}, - }, - }, + name: "Tests debugging", + findings: []finding.Finding{ + { + Outcome: finding.OutcomeNegative, + Probe: "testsRunInCI", + Message: "merged PR 1 without CI test at HEAD: 1", + Location: &finding.Location{Type: 4}, }, - dl: &scut.TestDetailLogger{}, - }, - want: true, - wantErr: false, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - got, err := prHasSuccessfulCheck(tt.args.r, tt.args.dl) - if (err != nil) != tt.wantErr { - t.Errorf("prHasSuccessfulCheck() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("prHasSuccessfulCheck() got = %v, want %v", got, tt.want) - } - }) - } -} - -func TestCITests(t *testing.T) { - t.Parallel() - type args struct { //nolint:govet - in0 string - c *checker.CITestData - dl checker.DetailLogger - } - tests := []struct { //nolint:govet - name string - args args - want int - }{ - { - name: "Status completed with failure", - args: args{ - in0: "", - c: &checker.CITestData{ - CIInfo: []checker.RevisionCIInfo{ - { - CheckRuns: []clients.CheckRun{ - { - Status: "completed", - App: clients.CheckRunApp{Slug: "e2e"}, - }, - }, - Statuses: []clients.Status{ - { - State: "failure", - Context: CheckCITests, - TargetURL: "e2e", - }, - }, - }, - }, + { + Outcome: finding.OutcomeNegative, + Probe: "testsRunInCI", + Message: "merged PR 1 without CI test at HEAD: 1", + Location: &finding.Location{Type: 4}, }, - dl: &scut.TestDetailLogger{}, - }, - want: 0, - }, - { - name: "valid", - args: args{ - in0: "", - c: &checker.CITestData{ - CIInfo: []checker.RevisionCIInfo{ - { - CheckRuns: []clients.CheckRun{ - { - Status: "completed", - Conclusion: "success", - App: clients.CheckRunApp{Slug: "e2e"}, - }, - }, - Statuses: []clients.Status{ - { - State: "success", - Context: CheckCITests, - TargetURL: "e2e", - }, - }, - }, - }, + { + Outcome: finding.OutcomeNegative, + Probe: "testsRunInCI", + Message: "merged PR 1 without CI test at HEAD: 1", + Location: &finding.Location{Type: 4}, }, - dl: &scut.TestDetailLogger{}, }, - want: 10, - }, - { - name: "no ci info", - args: args{ - in0: "", - c: &checker.CITestData{}, - dl: &scut.TestDetailLogger{}, + result: scut.TestReturn{ + NumberOfDebug: 3, + Score: 0, }, - want: -1, }, } - for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := CITests(tt.args.in0, tt.args.c, tt.args.dl); got.Score != tt.want { - t.Errorf("CITests() = %v, want %v", got.Score, tt.want) + dl := scut.TestDetailLogger{} + got := CITests(tt.name, tt.findings, &dl) + if !scut.ValidateTestReturn(t, tt.name, &tt.result, &got, &dl) { + t.Errorf("got %v, expected %v", got, tt.result) } }) } diff --git a/probes/entries.go b/probes/entries.go index 4486ecd8913..9f4f8ede19a 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -50,6 +50,7 @@ import ( "github.com/ossf/scorecard/v4/probes/securityPolicyContainsText" "github.com/ossf/scorecard/v4/probes/securityPolicyContainsVulnerabilityDisclosure" "github.com/ossf/scorecard/v4/probes/securityPolicyPresent" + "github.com/ossf/scorecard/v4/probes/testsRunInCI" "github.com/ossf/scorecard/v4/probes/toolDependabotInstalled" "github.com/ossf/scorecard/v4/probes/toolPyUpInstalled" "github.com/ossf/scorecard/v4/probes/toolRenovateInstalled" @@ -129,6 +130,9 @@ var ( Webhook = []ProbeImpl{ webhooksUseSecrets.Run, } + CITests = []ProbeImpl{ + testsRunInCI.Run, + } ) //nolint:gochecknoinits diff --git a/probes/testsRunInCI/def.yml b/probes/testsRunInCI/def.yml new file mode 100644 index 00000000000..447dbeaa78b --- /dev/null +++ b/probes/testsRunInCI/def.yml @@ -0,0 +1,28 @@ +# 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: testsRunInCI +short: Checks that the project runs tests in the CI for example with Github Actions or Prow. +motivation: > + Running tests helps developers catch mistakes early on, which can reduce the number of vulnerabilities that find their way into a project. +implementation: > + The probe checks for tests in the projects CI jobs in the recent commits (~30). +outcome: + - The probe returns one OutcomePositive for each PR that ran CI tests and one OutcomeNegative for each PR that did not run CI tests. + - The probe returns a single OutcomeNotApplicable if the projects has had no pull requests. +remediation: + effort: Medium + text: + - Check-in scripts that run all the tests in your repository. + - Integrate those scripts with a CI/CD platform that runs it on every pull request (e.g. if hosted on GitHub, [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions), [Prow](https://github.com/kubernetes/test-infra/tree/master/prow), etc). \ No newline at end of file diff --git a/probes/testsRunInCI/impl.go b/probes/testsRunInCI/impl.go new file mode 100644 index 00000000000..4ae9576943d --- /dev/null +++ b/probes/testsRunInCI/impl.go @@ -0,0 +1,169 @@ +// 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. + +//nolint:stylecheck +package testsRunInCI + +import ( + "embed" + "fmt" + "strings" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + Probe = "testsRunInCI" + success = "success" +) + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + var findings []finding.Finding + + c := raw.CITestResults + + if len(c.CIInfo) == 0 { + f, err := finding.NewWith(fs, Probe, + "no pull requests found", nil, + finding.OutcomeNotApplicable) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + return findings, Probe, nil + } + + for i := range c.CIInfo { + r := c.CIInfo[i] + // GitHub Statuses. + prSuccessStatus, f, err := prHasSuccessStatus(r) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + if prSuccessStatus { + findings = append(findings, *f) + continue + } + + // GitHub Check Runs. + prCheckSuccessful, f, err := prHasSuccessfulCheck(r) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + if prCheckSuccessful { + findings = append(findings, *f) + } + + if !prSuccessStatus && !prCheckSuccessful { + f, err := finding.NewWith(fs, Probe, + fmt.Sprintf("merged PR %d without CI test at HEAD: %s", r.PullRequestNumber, r.HeadSHA), + nil, finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + } + + return findings, Probe, nil +} + +// PR has a status marked 'success' and a CI-related context. +// +//nolint:unparam +func prHasSuccessStatus(r checker.RevisionCIInfo) (bool, *finding.Finding, error) { + for _, status := range r.Statuses { + if status.State != success { + continue + } + if isTest(status.Context) || isTest(status.TargetURL) { + msg := fmt.Sprintf("CI test found: pr: %s, context: %s", r.HeadSHA, + status.Context) + + f, err := finding.NewWith(fs, Probe, + msg, nil, + finding.OutcomePositive) + if err != nil { + return false, nil, fmt.Errorf("create finding: %w", err) + } + + loc := &finding.Location{ + Path: status.URL, + Type: finding.FileTypeURL, + } + f = f.WithLocation(loc) + return true, f, nil + } + } + return false, nil, nil +} + +// PR has a successful CI-related check. +// +//nolint:unparam +func prHasSuccessfulCheck(r checker.RevisionCIInfo) (bool, *finding.Finding, error) { + for _, cr := range r.CheckRuns { + if cr.Status != "completed" { + continue + } + if cr.Conclusion != success { + continue + } + if isTest(cr.App.Slug) { + msg := fmt.Sprintf("CI test found: pr: %d, context: %s", r.PullRequestNumber, + cr.App.Slug) + + f, err := finding.NewWith(fs, Probe, + msg, nil, + finding.OutcomePositive) + if err != nil { + return false, nil, fmt.Errorf("create finding: %w", err) + } + + loc := &finding.Location{ + Path: cr.URL, + Type: finding.FileTypeURL, + } + f = f.WithLocation(loc) + return true, f, nil + } + } + return false, nil, nil +} + +// isTest returns true if the given string is a CI test. +func isTest(s string) bool { + l := strings.ToLower(s) + + // Add more patterns here! + for _, pattern := range []string{ + "appveyor", "buildkite", "circleci", "e2e", "github-actions", "jenkins", + "mergeable", "packit-as-a-service", "semaphoreci", "test", "travis-ci", + "flutter-dashboard", "Cirrus CI", "azure-pipelines", + } { + if strings.Contains(l, pattern) { + return true + } + } + return false +} diff --git a/probes/testsRunInCI/impl_test.go b/probes/testsRunInCI/impl_test.go new file mode 100644 index 00000000000..670be5dfddb --- /dev/null +++ b/probes/testsRunInCI/impl_test.go @@ -0,0 +1,486 @@ +// 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. + +//nolint:stylecheck +package testsRunInCI + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" + scut "github.com/ossf/scorecard/v4/utests" +) + +const ( + // CheckCITests is the registered name for CITests. + CheckCITests = "CI-Tests" +) + +// Important: tests must include findings with values. +// Testing only for the outcome is insufficient, because the +// values of the findings are important to the probe. +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + findings []*finding.Finding + err error + }{ + { + name: "Has 1 CIInfo which has a successful CheckRun.", + raw: &checker.RawResults{ + CITestResults: checker.CITestData{ + CIInfo: []checker.RevisionCIInfo{ + { + HeadSHA: "HeadSHA", + PullRequestNumber: 1, + CheckRuns: []clients.CheckRun{ + { + Status: "completed", + Conclusion: "success", + App: clients.CheckRunApp{Slug: "e2e"}, + }, + }, + Statuses: []clients.Status{ + { + State: "not successful", + Context: CheckCITests, + TargetURL: "e2e", + }, + }, + }, + }, + }, + }, + findings: []*finding.Finding{ + { + Outcome: finding.OutcomePositive, + Probe: Probe, + Message: "CI test found: pr: 1, context: e2e", + Location: &finding.Location{Type: 4}, + }, + }, + }, + { + name: "Has 1 CIInfo which has a successful Status.", + raw: &checker.RawResults{ + CITestResults: checker.CITestData{ + CIInfo: []checker.RevisionCIInfo{ + { + HeadSHA: "HeadSHA", + PullRequestNumber: 1, + CheckRuns: []clients.CheckRun{ + { + Status: "incomplete", + Conclusion: "not successful", + App: clients.CheckRunApp{Slug: "e2e"}, + }, + }, + Statuses: []clients.Status{ + { + State: "success", + Context: CheckCITests, + TargetURL: "e2e", + }, + }, + }, + }, + }, + }, + findings: []*finding.Finding{ + { + Outcome: finding.OutcomePositive, + Probe: Probe, + Message: "CI test found: pr: HeadSHA, context: CI-Tests", + Location: &finding.Location{Type: 4}, + }, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.findings), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.findings { + outcome := &tt.findings[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} + +func Test_isTest(t *testing.T) { + t.Parallel() + type args struct { + s string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "appveyor", + args: args{ + s: "appveyor", + }, + want: true, + }, + { + name: "circleci", + args: args{ + s: "circleci", + }, + want: true, + }, + { + name: "jenkins", + args: args{ + s: "jenkins", + }, + want: true, + }, + { + name: "e2e", + args: args{ + s: "e2e", + }, + want: true, + }, + { + name: "github-actions", + args: args{ + s: "github-actions", + }, + want: true, + }, + { + name: "mergeable", + args: args{ + s: "mergeable", + }, + want: true, + }, + { + name: "packit-as-a-service", + args: args{ + s: "packit-as-a-service", + }, + want: true, + }, + { + name: "semaphoreci", + args: args{ + s: "semaphoreci", + }, + want: true, + }, + { + name: "test", + args: args{ + s: "test", + }, + want: true, + }, + { + name: "travis-ci", + args: args{ + s: "travis-ci", + }, + want: true, + }, + { + name: "azure-pipelines", + args: args{ + s: "azure-pipelines", + }, + want: true, + }, + { + name: "non-existing", + args: args{ + s: "non-existing", + }, + want: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := isTest(tt.args.s); got != tt.want { + t.Errorf("isTest() = %v, want %v for test %v", got, tt.want, tt.name) + } + }) + } +} + +func Test_prHasSuccessfulCheck(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + args checker.RevisionCIInfo + want bool + wantErr bool + }{ + { + name: "check run with conclusion success", + args: checker.RevisionCIInfo{ + PullRequestNumber: 1, + HeadSHA: "sha", + CheckRuns: []clients.CheckRun{ + { + App: clients.CheckRunApp{Slug: "test"}, + Conclusion: "success", + URL: "url", + Status: "completed", + }, + }, + }, + want: true, + wantErr: false, + }, + { + name: "check run with conclusion not success", + args: checker.RevisionCIInfo{ + PullRequestNumber: 1, + HeadSHA: "sha", + CheckRuns: []clients.CheckRun{ + { + App: clients.CheckRunApp{Slug: "test"}, + Conclusion: "failed", + URL: "url", + Status: "completed", + }, + }, + }, + want: false, + wantErr: false, + }, + { + name: "check run with conclusion not success", + args: checker.RevisionCIInfo{ + PullRequestNumber: 1, + HeadSHA: "sha", + CheckRuns: []clients.CheckRun{ + { + App: clients.CheckRunApp{Slug: "test"}, + Conclusion: "success", + URL: "url", + Status: "notcompleted", + }, + }, + }, + want: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + + //nolint:errcheck + got, _, _ := prHasSuccessfulCheck(tt.args) + if got != tt.want { + t.Errorf("prHasSuccessfulCheck() = %v, want %v", got, tt.want) + } + } +} + +func Test_prHasSuccessStatus(t *testing.T) { + t.Parallel() + type args struct { + r checker.RevisionCIInfo + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "empty revision", + args: args{ + r: checker.RevisionCIInfo{}, + }, + want: false, + wantErr: false, + }, + { + name: "no statuses", + args: args{ + r: checker.RevisionCIInfo{ + Statuses: []clients.Status{}, + }, + }, + }, + { + name: "status is not success", + args: args{ + r: checker.RevisionCIInfo{ + Statuses: []clients.Status{ + { + State: "failure", + }, + }, + }, + }, + }, + { + name: "status is success", + args: args{ + r: checker.RevisionCIInfo{ + Statuses: []clients.Status{ + { + State: "success", + Context: CheckCITests, + }, + }, + }, + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, _, err := prHasSuccessStatus(tt.args.r) + if (err != nil) != tt.wantErr { + t.Errorf("prHasSuccessStatus() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("prHasSuccessStatus() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_prHasSuccessfulCheckAdditional(t *testing.T) { + t.Parallel() + type args struct { //nolint:govet + r checker.RevisionCIInfo + dl checker.DetailLogger + } + tests := []struct { //nolint:govet + name string + args args + want bool + wantErr bool + }{ + { + name: "empty revision", + args: args{ + r: checker.RevisionCIInfo{}, + }, + want: false, + wantErr: false, + }, + { + name: "status is not completed", + args: args{ + r: checker.RevisionCIInfo{ + CheckRuns: []clients.CheckRun{ + { + Status: "notcompleted", + }, + }, + }, + }, + }, + { + name: "status is not success", + args: args{ + r: checker.RevisionCIInfo{ + CheckRuns: []clients.CheckRun{ + { + Status: "completed", + Conclusion: "failure", + }, + }, + }, + }, + }, + { + name: "conclusion is success", + args: args{ + r: checker.RevisionCIInfo{ + CheckRuns: []clients.CheckRun{ + { + Status: "completed", + Conclusion: "success", + }, + }, + }, + }, + }, + { + name: "conclusion is succesls with a valid app slug", + args: args{ + r: checker.RevisionCIInfo{ + CheckRuns: []clients.CheckRun{ + { + Status: "completed", + Conclusion: "success", + App: clients.CheckRunApp{Slug: "e2e"}, + }, + }, + }, + dl: &scut.TestDetailLogger{}, + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, _, err := prHasSuccessfulCheck(tt.args.r) + if (err != nil) != tt.wantErr { + t.Errorf("prHasSuccessfulCheck() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("prHasSuccessfulCheck() got = %v, want %v", got, tt.want) + } + }) + } +} From db7b6e70af4cbf182d2f9d9a8f45ec205cf99021 Mon Sep 17 00:00:00 2001 From: Diogo Teles Sant'Anna Date: Tue, 12 Dec 2023 03:39:02 -0300 Subject: [PATCH 41/51] :sparkles: branch protection: requiring PRs gives partial credit (#3499) * feat(branch-protection): consider if project requires PRs prior to make changes As discussed at the issue #2727, we're adding the "require PRs prior to make changes" as another requirement to tier 2. In addition to that, we're changing the weight of the tier 2 requirements so that "requiring 1 reviewer" has weight 2, while the other tier 2 requirements have weight 1 Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): increment and adapt testing 1. Adapt previous test cases to consider that now we'll have an aditional Info log telling that the project requires PRs to make changes. 2. Add more cases to test relevant use cases on the tier 2 level of branch protection Signed-off-by: Diogo Teles Sant'Anna * docs(branch-protection-check): adapt check description to consider requirement of require PRs to make changes It adds the new tier 2 requirement, but also specify that the "require at least 1 reviewer" will have doubled weight. Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection-check): avoid duplicate funcions and enhance readability Made some nice-to-have improvements on project readability, making it easier easier to understand how the branch-protection score is computed. Also unified 8 different functions that were doing basically the same thing. Signed-off-by: Diogo Teles Sant'Anna * feat(branch-protection): standardize values received on evaluation Previously, at the evaluation part of branch protetion, the values nil and false or zero were sort of interchangeble. This commit changes the code to set as nil only the data that could not be retrieved from github -- all the others would have values as false, zero, true, etc Signed-off-by: Diogo Teles Sant'Anna * test(github-client): adapt and add tests to check if nil values are coherent 1. Add new test to evaluate how we're interpreting a rule with all checkboxes unchecked (most shouldn't be nil) 2. Adapt existent tests to expect non-nil values for unchecked checkboxes Signed-off-by: Diogo Teles Sant'Anna * feat(client-github): avoid reusing bool pointers Changes some pieces of code to prefer using pointers of bool instantiated independently. If reusing bool pointers, at some piece of code the value of the bool could inadvertently changed and it would change the value of all other fields reusing that pointer. Signed-off-by: Diogo Teles Sant'Anna * feat(branch-protection): enhance evaluation if scorecard was run by admin At the evaluation step we were using some non untrusted fieldds of the resposte to evaluate if Scorecard was run as admin or not. Now we're using a field provided directly from the client file. Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): adapt testings to say if they have admin info or not After last commit, the client will tell the evaluation files if Scorecard was run by administrator or not (i.e., if we have all the infos). This commit adapts the testings to also provide this info. Signed-off-by: Diogo Teles Sant'Anna * test(e2e-branch-protection): adapt number of logs after changes - 2 warns (for 'last push approval' and 'codeowners review' disabled) were added because now those informations come as 'not-nil' at the evaluation part. - 1 info was added to say that PRs are required to make changes - 1 debug was removed because it said that we couldn't retrieve 'last push approval' information, but we actually can. It was just incorrectly set as nil Signed-off-by: Diogo Teles Sant'Anna * Revert the 2 commits with changes around how Scorecard detects admin run Reverts commit 64c3521d89a6493e0d8c7527aa011f98c3e35719 and commit e2662b7173ef90b44b2d72c37614230440e8a919. Both had chances around using clients/branch.go scructur to store the information of whether Scorecard was being run by admin or not. We decided to not change this structure for this purpose. Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): change data structure to use pointer instead of value At clients.BranchProtectionRule struct, changing RequiredPullRequestReviews to be a pointer instead of a struct value. This will allow the usage of the nil value of this structure to mean that we can't say if the repository requires reviews or not. Signed-off-by: Diogo Teles Sant'Anna * feat(branch-protection): use nil pointer on reviewers struct to mean we don't know if they require PRs The nil value of the struct RequiredPullRequestReviews will now mean that we can't tell whether the project requires PRs to make changes or not. When we get this case, we're printing a debug informing that we don't have this data, but also printing a warn saying that they don't require reviews, because that will be true at this case. Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): if we're setting the reviewers struct to nil when needed Signed-off-by: Diogo Teles Sant'Anna * doc(branch-protection): add code comment explaining different weight on tier 2 scores Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): avoid duplicate if branches on reviewers num comparation Signed-off-by: Diogo Teles Sant'Anna * docs(branch-protection): clarify commentings around data structure Signed-off-by: Diogo Teles Sant'Anna * refactor: clean code on parsing GitHub BP data Signed-off-by: Diogo Teles Sant'Anna * feat(branch-protection): ressignify the nil PullRequestReviewRule to mean PR not required Adapt translation of data from GitHub API, now for our internal data modeling, having a nil PullRequestReviewRule structure will mean that PRs are not required on the repo (can also mean we don't have data to ensure that). It also changes the order of the calls of copyNonAdminSettings and copyAdminSettings to make the first one be called first. This eases the code because the PullRequestReviewRule can be always instantiated at this function. Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): ensure we translate GitHub BP data as expected Ensure we're correctly translating GitHub data from the old Branch Protection config. Signed-off-by: Diogo Teles Sant'Anna * feat(branch-protection): adapt score evaluation after 2efeee6512603ac48db78db2d2551c9b65d59462 Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): adapt testings to changes of last commits Signed-off-by: Diogo Teles Sant'Anna * docs(branch-protection): add TODO comments pointing refactor opportunities Signed-off-by: Diogo Teles Sant'Anna * fix: avoid penalyzing non-admin for dismissStaleReview Signed-off-by: Diogo Teles Sant'Anna * fix(branch-protection): prevent false value from API field to become nil When translating the API results, if the specific field `DismissesStaleReviews` had a false value, it was not being initiated in our data model and was remaining nil. Signed-off-by: Diogo Teles Sant'Anna * refactor: clarify different weight on first reviewer Signed-off-by: Diogo Teles Sant'Anna * refactor: enhance clarity of loggings and comments Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): new test to cover different rules affecting same branch Signed-off-by: Diogo Teles Sant'Anna * docs(branch-protection): change requirements ordering to keep admin ones together Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): simplify auxiliary function Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): fix code format to linter requirements Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): avoid unnecessary initializations and rename function Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): adapt test that was forgotten on commit 6858790a3e41d7f98e94a63a70b35e58300aad89 Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): use enums to represent tiers Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): remove nil fields of struct initialization when they dont contribute for clarification Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): simplify functions by using generics Signed-off-by: Diogo Teles Sant'Anna * docs(branch-protection): update docs after generate-docs run Signed-off-by: Diogo Teles Sant'Anna * fix(branch-protection): fix duplicated line on code Signed-off-by: Diogo Teles Sant'Anna * fix(branch-protection): stop exporting Tier enum Signed-off-by: Diogo Teles Sant'Anna * refactor(branch-protection): changing unchanged var to const Signed-off-by: Diogo Teles Sant'Anna * test(branch-protection): Rename test and adapt it to be consistent with its purpose I also changed the test to not require PRs, as it's how it is when a new GitHub Branch Protection config is created. The changes on the loggings numbers are due to: 1. A warning for not having DismissStaleReviews became a debug 2. Removed the warning we had for not requiring CodeOwners 3. Have a new warning for not requiring PRe Signed-off-by: Diogo Teles Sant'Anna --------- Signed-off-by: Diogo Teles Sant'Anna --- checks/branch_protection_test.go | 30 +- checks/evaluation/branch_protection.go | 172 ++++----- checks/evaluation/branch_protection_test.go | 218 +++++++++-- clients/branch.go | 6 +- clients/githubrepo/branches.go | 144 +++++--- clients/githubrepo/branches_test.go | 383 ++++++++++++++++---- clients/gitlabrepo/branches.go | 2 +- cron/internal/format/json_raw_results.go | 8 +- docs/checks.md | 3 +- docs/checks/internal/checks.yaml | 3 +- e2e/branch_protection_test.go | 10 +- pkg/json_raw_results.go | 8 +- pkg/json_raw_results_test.go | 2 +- 13 files changed, 709 insertions(+), 280 deletions(-) diff --git a/checks/branch_protection_test.go b/checks/branch_protection_test.go index c96a902b411..69c0ddd35ff 100644 --- a/checks/branch_protection_test.go +++ b/checks/branch_protection_test.go @@ -86,7 +86,6 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { defaultBranch: main, branches: []*clients.BranchRef{ { - Name: nil, Protected: &trueVal, BranchProtectionRule: clients.BranchProtectionRule{ CheckRules: clients.StatusChecksRule{ @@ -94,7 +93,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -106,7 +105,6 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { }, }, { - Name: nil, Protected: &trueVal, BranchProtectionRule: clients.BranchProtectionRule{ CheckRules: clients.StatusChecksRule{ @@ -114,7 +112,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -135,7 +133,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { Error: nil, Score: 3, NumberOfWarn: 7, - NumberOfInfo: 2, + NumberOfInfo: 3, NumberOfDebug: 0, }, defaultBranch: main, @@ -153,7 +151,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -174,7 +172,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { Error: nil, Score: 4, NumberOfWarn: 9, - NumberOfInfo: 10, + NumberOfInfo: 12, NumberOfDebug: 0, }, defaultBranch: main, @@ -188,7 +186,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -209,7 +207,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -230,7 +228,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { Error: nil, Score: 8, NumberOfWarn: 4, - NumberOfInfo: 16, + NumberOfInfo: 18, NumberOfDebug: 0, }, defaultBranch: main, @@ -244,7 +242,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -265,7 +263,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -286,7 +284,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { Error: nil, Score: 3, NumberOfWarn: 7, - NumberOfInfo: 2, + NumberOfInfo: 3, NumberOfDebug: 0, }, defaultBranch: main, @@ -301,7 +299,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -339,7 +337,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -357,7 +355,7 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { expected: scut.TestReturn{ Error: nil, Score: 0, - NumberOfWarn: 4, + NumberOfWarn: 6, NumberOfInfo: 0, NumberOfDebug: 8, }, diff --git a/checks/evaluation/branch_protection.go b/checks/evaluation/branch_protection.go index 1a66347c663..21352fb789a 100644 --- a/checks/evaluation/branch_protection.go +++ b/checks/evaluation/branch_protection.go @@ -49,6 +49,16 @@ type levelScore struct { maxes scoresInfo // Maximum possible score for a branch. } +type tier uint8 + +const ( + Tier1 tier = iota + Tier2 + Tier3 + Tier4 + Tier5 +) + // BranchProtection runs Branch-Protection check. func BranchProtection(name string, dl checker.DetailLogger, r *checker.BranchProtectionsData, @@ -85,7 +95,7 @@ func BranchProtection(name string, dl checker.DetailLogger, return checker.CreateInconclusiveResult(name, "unable to detect any development/release branches") } - score, err := computeScore(scores) + score, err := computeFinalScore(scores) if err != nil { return checker.CreateRuntimeErrorResult(name, err) } @@ -103,77 +113,34 @@ func BranchProtection(name string, dl checker.DetailLogger, } } -func computeNonAdminBasicScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.basic - } - return score -} - -func computeNonAdminReviewScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.review - } - return score -} - -func computeAdminReviewScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.adminReview - } - return score -} - -func computeNonAdminThoroughReviewScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.thoroughReview - } - return score -} - -func computeAdminThoroughReviewScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.adminThoroughReview - } - return score -} - -func computeNonAdminContextScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.context - } - return score -} - -func computeCodeownerThoroughReviewScore(scores []levelScore) int { - score := 0 - for i := range scores { - s := scores[i] - score += s.scores.codeownerReview +func sumUpScoreForTier(t tier, scoresData []levelScore) int { + sum := 0 + for i := range scoresData { + score := scoresData[i] + switch t { + case Tier1: + sum += score.scores.basic + case Tier2: + sum += score.scores.review + score.scores.adminReview + case Tier3: + sum += score.scores.context + case Tier4: + sum += score.scores.thoroughReview + score.scores.codeownerReview + case Tier5: + sum += score.scores.adminThoroughReview + } } - return score + return sum } -func noarmalizeScore(score, max, level int) float64 { +func normalizeScore(score, max, level int) float64 { if max == 0 { return float64(level) } return float64(score*level) / float64(max) } -func computeScore(scores []levelScore) (int, error) { +func computeFinalScore(scores []levelScore) (int, error) { if len(scores) == 0 { return 0, sce.WithMessage(sce.ErrScorecardInternal, "scores are empty") } @@ -183,28 +150,26 @@ func computeScore(scores []levelScore) (int, error) { // First, check if they all pass the basic (admin and non-admin) checks. maxBasicScore := maxScore.basic * len(scores) - basicScore := computeNonAdminBasicScore(scores) - score += noarmalizeScore(basicScore, maxBasicScore, basicLevel) - if basicScore != maxBasicScore { + basicScore := sumUpScoreForTier(Tier1, scores) + score += normalizeScore(basicScore, maxBasicScore, basicLevel) + if basicScore < maxBasicScore { return int(score), nil } // Second, check the (admin and non-admin) reviews. maxReviewScore := maxScore.review * len(scores) maxAdminReviewScore := maxScore.adminReview * len(scores) - reviewScore := computeNonAdminReviewScore(scores) - adminReviewScore := computeAdminReviewScore(scores) - score += noarmalizeScore(reviewScore+adminReviewScore, maxReviewScore+maxAdminReviewScore, adminNonAdminReviewLevel) - if reviewScore != maxReviewScore || - adminReviewScore != maxAdminReviewScore { + adminNonAdminReviewScore := sumUpScoreForTier(Tier2, scores) + score += normalizeScore(adminNonAdminReviewScore, maxReviewScore+maxAdminReviewScore, adminNonAdminReviewLevel) + if adminNonAdminReviewScore < maxReviewScore+maxAdminReviewScore { return int(score), nil } // Third, check the use of non-admin context. maxContextScore := maxScore.context * len(scores) - contextScore := computeNonAdminContextScore(scores) - score += noarmalizeScore(contextScore, maxContextScore, nonAdminContextLevel) - if contextScore != maxContextScore { + contextScore := sumUpScoreForTier(Tier3, scores) + score += normalizeScore(contextScore, maxContextScore, nonAdminContextLevel) + if contextScore < maxContextScore { return int(score), nil } @@ -212,11 +177,9 @@ func computeScore(scores []levelScore) (int, error) { // Also check whether this repo requires codeowner review maxThoroughReviewScore := maxScore.thoroughReview * len(scores) maxCodeownerReviewScore := maxScore.codeownerReview * len(scores) - thoroughReviewScore := computeNonAdminThoroughReviewScore(scores) - codeownerReviewScore := computeCodeownerThoroughReviewScore(scores) - score += noarmalizeScore(thoroughReviewScore+codeownerReviewScore, maxThoroughReviewScore+maxCodeownerReviewScore, - nonAdminThoroughReviewLevel) - if thoroughReviewScore != maxThoroughReviewScore { + tier4Score := sumUpScoreForTier(Tier4, scores) + score += normalizeScore(tier4Score, maxThoroughReviewScore+maxCodeownerReviewScore, nonAdminThoroughReviewLevel) + if tier4Score < maxThoroughReviewScore+maxCodeownerReviewScore { return int(score), nil } @@ -224,8 +187,8 @@ func computeScore(scores []levelScore) (int, error) { // This one is controversial and has usability issues // https://github.com/ossf/scorecard/issues/1027, so we may remove it. maxAdminThoroughReviewScore := maxScore.adminThoroughReview * len(scores) - adminThoroughReviewScore := computeAdminThoroughReviewScore(scores) - score += noarmalizeScore(adminThoroughReviewScore, maxAdminThoroughReviewScore, adminThoroughReviewLevel) + adminThoroughReviewScore := sumUpScoreForTier(Tier5, scores) + score += normalizeScore(adminThoroughReviewScore, maxAdminThoroughReviewScore, adminThoroughReviewLevel) if adminThoroughReviewScore != maxAdminThoroughReviewScore { return int(score), nil } @@ -319,11 +282,14 @@ func nonAdminReviewProtection(branch *clients.BranchRef) (int, int) { score := 0 max := 0 - max++ - if branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount != nil && + // Having at least 1 reviewer is twice as important as the other Tier 2 requirements. + const reviewerWeight = 2 + max += reviewerWeight + if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && + branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount != nil && *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount > 0 { // We do not display anything here, it's done in nonAdminThoroughReviewProtection() - score++ + score += reviewerWeight } return score, max } @@ -362,6 +328,18 @@ func adminReviewProtection(branch *clients.BranchRef, dl checker.DetailLogger) ( } } + max++ + if branch.BranchProtectionRule.RequiredPullRequestReviews != nil { + score++ + info(dl, log, "PRs are required in order to make changes on branch '%s'", *branch.Name) + } else { + warn(dl, log, "PRs are not required to make changes on branch '%s'; or we don't have data to detect it."+ + "If you think it might be the latter, make sure to run Scorecard with a PAT or use Repo "+ + "Rules (that are always public) instead of Branch Protection settings", *branch.Name) + // Warning it here because since `RequiredPullRequestReviews` is nil, we won't check reviewers count afterwards + warn(dl, log, "No reviewers required to merge changes on branch '%s'", *branch.Name) + } + return score, max } @@ -371,8 +349,9 @@ func adminThoroughReviewProtection(branch *clients.BranchRef, dl checker.DetailL // Only log information if the branch is protected. log := branch.Protected != nil && *branch.Protected - if branch.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews != nil { - // Note: we don't inrecase max possible score for non-admin viewers. + if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && + branch.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews != nil { + // Note: we don't increase max possible score for non-admin viewers. max++ switch *branch.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews { case true: @@ -411,19 +390,21 @@ func nonAdminThoroughReviewProtection(branch *clients.BranchRef, dl checker.Deta log := branch.Protected != nil && *branch.Protected max++ - if branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount != nil { - switch *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount >= minReviews { - case true: + + // On this first check we exclude the case where PRs are not required to make changes, + // because it's already covered on adminReviewProtection function. + if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && + branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount != nil { + if *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount >= minReviews { info(dl, log, "number of required reviewers is %d on branch '%s'", *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, *branch.Name) score++ - default: - warn(dl, log, "number of required reviewers is only %d on branch '%s'", - *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, *branch.Name) + } else { + warn(dl, log, "number of required reviewers is %d on branch '%s', while the ideal suggested is %d", + *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, *branch.Name, minReviews) } - } else { - warn(dl, log, "number of required reviewers is 0 on branch '%s'", *branch.Name) } + return score, max } @@ -435,7 +416,8 @@ func codeownerBranchProtection( log := branch.Protected != nil && *branch.Protected - if branch.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews != nil { + if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && + branch.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews != nil { switch *branch.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews { case true: info(dl, log, "codeowner review is required on branch '%s'", *branch.Name) diff --git a/checks/evaluation/branch_protection_test.go b/checks/evaluation/branch_protection_test.go index 2b45d116714..db25faf236b 100644 --- a/checks/evaluation/branch_protection_test.go +++ b/checks/evaluation/branch_protection_test.go @@ -32,9 +32,10 @@ func testScore(branch *clients.BranchRef, codeownersFiles []string, dl checker.D score.scores.adminThoroughReview, score.maxes.adminThoroughReview = adminThoroughReviewProtection(branch, dl) score.scores.codeownerReview, score.maxes.codeownerReview = codeownerBranchProtection(branch, codeownersFiles, dl) - return computeScore([]levelScore{score}) + return computeFinalScore([]levelScore{score}) } +// TODO: order of tests to have progressive scores. func TestIsBranchProtected(t *testing.T) { t.Parallel() trueVal := true @@ -49,28 +50,24 @@ func TestIsBranchProtected(t *testing.T) { expected scut.TestReturn }{ { - name: "Nothing is enabled", + name: "Configs as they are right after creating new Branch Protection setting", expected: scut.TestReturn{ Error: nil, Score: 3, - NumberOfWarn: 7, + NumberOfWarn: 6, NumberOfInfo: 2, - NumberOfDebug: 0, + NumberOfDebug: 1, }, branch: &clients.BranchRef{ Name: &branchVal, Protected: &trueVal, BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - RequireLinearHistory: &falseVal, - EnforceAdmins: &falseVal, - RequireLastPushApproval: &falseVal, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ - DismissStaleReviews: &falseVal, - RequireCodeOwnerReviews: &falseVal, - RequiredApprovingReviewCount: &zeroVal, - }, + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + RequireLinearHistory: &falseVal, + EnforceAdmins: &falseVal, + RequireLastPushApproval: &falseVal, + RequiredPullRequestReviews: nil, CheckRules: clients.StatusChecksRule{ RequiresStatusChecks: &trueVal, Contexts: nil, @@ -84,7 +81,7 @@ func TestIsBranchProtected(t *testing.T) { expected: scut.TestReturn{ Error: nil, Score: 0, - NumberOfWarn: 2, + NumberOfWarn: 3, NumberOfInfo: 0, NumberOfDebug: 4, }, @@ -99,14 +96,14 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 4, NumberOfWarn: 5, - NumberOfInfo: 4, + NumberOfInfo: 5, NumberOfDebug: 0, }, branch: &clients.BranchRef{ Name: &branchVal, Protected: &trueVal, BranchProtectionRule: clients.BranchProtectionRule{ - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -130,7 +127,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 4, NumberOfWarn: 6, - NumberOfInfo: 3, + NumberOfInfo: 4, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -142,7 +139,7 @@ func TestIsBranchProtected(t *testing.T) { RequireLinearHistory: &falseVal, AllowForcePushes: &falseVal, AllowDeletions: &falseVal, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -156,13 +153,13 @@ func TestIsBranchProtected(t *testing.T) { }, }, { - name: "Required pull request enabled", + name: "Admin run only preventing force pushes and deletions", expected: scut.TestReturn{ Error: nil, - Score: 4, + Score: 3, NumberOfWarn: 6, - NumberOfInfo: 3, - NumberOfDebug: 0, + NumberOfInfo: 2, + NumberOfDebug: 1, }, branch: &clients.BranchRef{ Name: &branchVal, @@ -170,15 +167,100 @@ func TestIsBranchProtected(t *testing.T) { BranchProtectionRule: clients.BranchProtectionRule{ EnforceAdmins: &falseVal, RequireLastPushApproval: &falseVal, + RequireLinearHistory: &falseVal, + AllowForcePushes: &falseVal, + AllowDeletions: &falseVal, + CheckRules: clients.StatusChecksRule{ + RequiresStatusChecks: &falseVal, + UpToDateBeforeMerge: &falseVal, + Contexts: nil, + }, + RequiredPullRequestReviews: nil, + }, + }, + }, + { + name: "Admin run with all tier 2 requirements except require PRs and reviewers", + expected: scut.TestReturn{ + Error: nil, + Score: 4, // Should be 4.2 if we allow decimal puctuation + NumberOfWarn: 2, + NumberOfInfo: 6, + NumberOfDebug: 1, + }, + branch: &clients.BranchRef{ + Name: &branchVal, + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + EnforceAdmins: &trueVal, + RequireLastPushApproval: &trueVal, + RequireLinearHistory: &trueVal, + AllowForcePushes: &falseVal, + AllowDeletions: &falseVal, + CheckRules: clients.StatusChecksRule{ + RequiresStatusChecks: &falseVal, + UpToDateBeforeMerge: &trueVal, + Contexts: []string{"foo"}, + }, + RequiredPullRequestReviews: nil, + }, + }, + }, + { + name: "Admin run on project requiring pull requests but without approver -- best a single maintainer can do", + expected: scut.TestReturn{ + Error: nil, + Score: 4, // Should be 4.8 if we allow decimal punctuation + NumberOfWarn: 2, + NumberOfInfo: 9, + NumberOfDebug: 0, + }, + branch: &clients.BranchRef{ + Name: &branchVal, + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + EnforceAdmins: &trueVal, + RequireLastPushApproval: &trueVal, RequireLinearHistory: &trueVal, AllowForcePushes: &falseVal, AllowDeletions: &falseVal, CheckRules: clients.StatusChecksRule{ RequiresStatusChecks: &trueVal, - UpToDateBeforeMerge: &falseVal, + UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + DismissStaleReviews: &trueVal, + RequireCodeOwnerReviews: &trueVal, + RequiredApprovingReviewCount: &zeroVal, + }, + }, + }, + }, + { + name: "Admin run on project with all tier 2 requirements", + expected: scut.TestReturn{ + Error: nil, + Score: 6, + NumberOfWarn: 4, + NumberOfInfo: 6, + NumberOfDebug: 0, + }, + branch: &clients.BranchRef{ + Name: &branchVal, + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + EnforceAdmins: &trueVal, + RequireLastPushApproval: &trueVal, + RequireLinearHistory: &trueVal, + AllowForcePushes: &falseVal, + AllowDeletions: &falseVal, + CheckRules: clients.StatusChecksRule{ + RequiresStatusChecks: &falseVal, + UpToDateBeforeMerge: &trueVal, + Contexts: nil, + }, + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &oneVal, @@ -186,13 +268,71 @@ func TestIsBranchProtected(t *testing.T) { }, }, }, + { + name: "Non-admin run on project that require zero reviewer (or don't require PRs at all, we can't differentiate it)", + expected: scut.TestReturn{ + Error: nil, + Score: 3, + NumberOfWarn: 3, + NumberOfInfo: 2, + NumberOfDebug: 4, + }, + branch: &clients.BranchRef{ + Name: &branchVal, + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + EnforceAdmins: nil, + RequireLastPushApproval: nil, + RequireLinearHistory: &falseVal, + AllowForcePushes: &falseVal, + AllowDeletions: &falseVal, + CheckRules: clients.StatusChecksRule{ + RequiresStatusChecks: nil, + UpToDateBeforeMerge: nil, + Contexts: nil, + }, + RequiredPullRequestReviews: nil, + }, + }, + }, + { + name: "Non-admin run on project that require 1 reviewer", + expected: scut.TestReturn{ + Error: nil, + Score: 6, + NumberOfWarn: 3, + NumberOfInfo: 3, + NumberOfDebug: 4, + }, + branch: &clients.BranchRef{ + Name: &branchVal, + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + EnforceAdmins: nil, + RequireLastPushApproval: nil, + RequireLinearHistory: &falseVal, + AllowForcePushes: &falseVal, + AllowDeletions: &falseVal, + CheckRules: clients.StatusChecksRule{ + RequiresStatusChecks: nil, + UpToDateBeforeMerge: nil, + Contexts: nil, + }, + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + DismissStaleReviews: nil, + RequireCodeOwnerReviews: &falseVal, + RequiredApprovingReviewCount: &oneVal, + }, + }, + }, + }, { name: "Required admin enforcement enabled", expected: scut.TestReturn{ Error: nil, Score: 3, NumberOfWarn: 5, - NumberOfInfo: 4, + NumberOfInfo: 5, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -209,7 +349,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -223,7 +363,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 3, NumberOfWarn: 6, - NumberOfInfo: 3, + NumberOfInfo: 4, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -240,7 +380,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -254,7 +394,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 1, NumberOfWarn: 7, - NumberOfInfo: 2, + NumberOfInfo: 3, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -272,7 +412,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -286,7 +426,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 1, NumberOfWarn: 7, - NumberOfInfo: 2, + NumberOfInfo: 3, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -303,7 +443,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -317,7 +457,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 8, NumberOfWarn: 2, - NumberOfInfo: 8, + NumberOfInfo: 9, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -334,7 +474,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -348,7 +488,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 8, NumberOfWarn: 1, - NumberOfInfo: 8, + NumberOfInfo: 9, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -365,7 +505,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -380,7 +520,7 @@ func TestIsBranchProtected(t *testing.T) { Error: nil, Score: 5, NumberOfWarn: 3, - NumberOfInfo: 7, + NumberOfInfo: 8, NumberOfDebug: 0, }, branch: &clients.BranchRef{ @@ -397,7 +537,7 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, diff --git a/clients/branch.go b/clients/branch.go index ff11e4a683e..4cd6b3d4217 100644 --- a/clients/branch.go +++ b/clients/branch.go @@ -23,7 +23,11 @@ type BranchRef struct { // BranchProtectionRule captures the settings enabled on a branch for security. type BranchProtectionRule struct { - RequiredPullRequestReviews PullRequestReviewRule + // The nil value of this struct can mean either: + // 1. we can't tell if PRs are required to make changes; or + // 2. we know PRs are not required. The first case happens when Scorecard is run without admin token on + // a repo that uses the old Branch Protection setting (not the new Repo Rules, that are always public). + RequiredPullRequestReviews *PullRequestReviewRule AllowDeletions *bool AllowForcePushes *bool RequireLinearHistory *bool diff --git a/clients/githubrepo/branches.go b/clients/githubrepo/branches.go index 115c21964b6..b8ba122ef8e 100644 --- a/clients/githubrepo/branches.go +++ b/clients/githubrepo/branches.go @@ -323,10 +323,10 @@ func (handler *branchesHandler) getBranch(branch string) (*clients.BranchRef, er return branchRef, nil } +// TODO: Move these two functions to below the GetBranchRefFrom functions, the single place they're used. func copyAdminSettings(src *branchProtectionRule, dst *clients.BranchProtectionRule) { copyBoolPtr(src.IsAdminEnforced, &dst.EnforceAdmins) copyBoolPtr(src.RequireLastPushApproval, &dst.RequireLastPushApproval) - copyBoolPtr(src.DismissesStaleReviews, &dst.RequiredPullRequestReviews.DismissStaleReviews) if src.RequiresStatusChecks != nil { copyBoolPtr(src.RequiresStatusChecks, &dst.CheckRules.RequiresStatusChecks) // TODO(#3255): Update when GitHub GraphQL bug is fixed @@ -340,6 +340,15 @@ func copyAdminSettings(src *branchProtectionRule, dst *clients.BranchProtectionR copyBoolPtr(&upToDateBeforeMerge, &dst.CheckRules.UpToDateBeforeMerge) } } + + // We're also checking if branch requires PRs because if it doesn't, + // the RequiredPullRequestReviews struct should be nil. + if src.DismissesStaleReviews != nil && branchRequiresPrs(src) { + if dst.RequiredPullRequestReviews == nil { + dst.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) + } + copyBoolPtr(src.DismissesStaleReviews, &dst.RequiredPullRequestReviews.DismissStaleReviews) + } } func copyNonAdminSettings(src interface{}, dst *clients.BranchProtectionRule) { @@ -349,20 +358,39 @@ func copyNonAdminSettings(src interface{}, dst *clients.BranchProtectionRule) { copyBoolPtr(v.AllowsDeletions, &dst.AllowDeletions) copyBoolPtr(v.AllowsForcePushes, &dst.AllowForcePushes) copyBoolPtr(v.RequiresLinearHistory, &dst.RequireLinearHistory) - copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) - copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) copyStringSlice(v.RequiredStatusCheckContexts, &dst.CheckRules.Contexts) + // If branch doesn't require PRs to make changes, we let the struct RequiredPullRequestReviews point to nil + if branchRequiresPrs(v) { + if dst.RequiredPullRequestReviews == nil { + dst.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) + } + copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) + copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) + } + case *refUpdateRule: copyBoolPtr(v.AllowsDeletions, &dst.AllowDeletions) copyBoolPtr(v.AllowsForcePushes, &dst.AllowForcePushes) copyBoolPtr(v.RequiresLinearHistory, &dst.RequireLinearHistory) - copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) - copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) copyStringSlice(v.RequiredStatusCheckContexts, &dst.CheckRules.Contexts) + + // Evaluate if we have data to infer that the project requires PRs to make changes. If we don't have data, we let + // the struct RequiredPullRequestReviews as nil + if valueOrZero(v.RequiredApprovingReviewCount) > 0 || valueOrZero(v.RequiresCodeOwnerReviews) { + if dst.RequiredPullRequestReviews == nil { + dst.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) + } + copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) + copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) + } } } +func branchRequiresPrs(data *branchProtectionRule) bool { + return data.RequiredApprovingReviewCount != nil +} + func getDefaultBranchNameFrom(data *ruleSetData) string { if data == nil || data.Repository.DefaultBranchRef.Name == nil { return "" @@ -411,12 +439,12 @@ func getBranchRefFrom(data *branch, rules []*repoRuleSet) *clients.BranchRef { case data.BranchProtectionRule != nil: rule := data.BranchProtectionRule - // Admin settings. - copyAdminSettings(rule, branchRule) - // Non-admin settings. copyNonAdminSettings(rule, branchRule) + // Admin settings. + copyAdminSettings(rule, branchRule) + // Only non-admin settings are available. // https://docs.github.com/en/graphql/reference/objects#refupdaterule. case data.RefUpdateRule != nil: @@ -477,22 +505,24 @@ nextRule: } func applyRepoRules(branchRef *clients.BranchRef, rules []*repoRuleSet) { - falseVal := false - trueVal := true for _, r := range rules { - adminEnforced := len(r.BypassActors.Nodes) == 0 + // Init values of base checkbox as if they're unchecked translated := clients.BranchProtectionRule{ - EnforceAdmins: &adminEnforced, + AllowDeletions: asPtr(true), + AllowForcePushes: asPtr(true), + RequireLinearHistory: asPtr(false), } + translated.EnforceAdmins = asPtr(len(r.BypassActors.Nodes) == 0) + for _, rule := range r.Rules.Nodes { switch rule.Type { case ruleDeletion: - translated.AllowDeletions = &falseVal + translated.AllowDeletions = asPtr(false) case ruleForcePush: - translated.AllowForcePushes = &falseVal + translated.AllowForcePushes = asPtr(false) case ruleLinear: - translated.RequireLinearHistory = &trueVal + translated.RequireLinearHistory = asPtr(true) case rulePullRequest: translatePullRequestRepoRule(&translated, rule) case ruleStatusCheck: @@ -504,18 +534,13 @@ func applyRepoRules(branchRef *clients.BranchRef, rules []*repoRuleSet) { } func translatePullRequestRepoRule(base *clients.BranchProtectionRule, rule *repoRule) { - if readBoolPtr(rule.Parameters.PullRequestParameters.DismissStaleReviewsOnPush) { - base.RequiredPullRequestReviews.DismissStaleReviews = rule.Parameters.PullRequestParameters.DismissStaleReviewsOnPush - } - if readBoolPtr(rule.Parameters.PullRequestParameters.RequireCodeOwnerReview) { - base.RequiredPullRequestReviews.RequireCodeOwnerReviews = rule.Parameters.PullRequestParameters.RequireCodeOwnerReview - } - if readBoolPtr(rule.Parameters.PullRequestParameters.RequireLastPushApproval) { - base.RequireLastPushApproval = rule.Parameters.PullRequestParameters.RequireLastPushApproval - } - if reviewerCount := readIntPtr(rule.Parameters.PullRequestParameters.RequiredApprovingReviewCount); reviewerCount > 0 { - base.RequiredPullRequestReviews.RequiredApprovingReviewCount = &reviewerCount - } + base.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) + + base.RequiredPullRequestReviews.DismissStaleReviews = rule.Parameters.PullRequestParameters.DismissStaleReviewsOnPush + base.RequiredPullRequestReviews.RequireCodeOwnerReviews = rule.Parameters.PullRequestParameters.RequireCodeOwnerReview + base.RequireLastPushApproval = rule.Parameters.PullRequestParameters.RequireLastPushApproval + base.RequiredPullRequestReviews.RequiredApprovingReviewCount = rule.Parameters.PullRequestParameters. + RequiredApprovingReviewCount } func translateRequiredStatusRepoRule(base *clients.BranchProtectionRule, rule *repoRule) { @@ -523,8 +548,7 @@ func translateRequiredStatusRepoRule(base *clients.BranchProtectionRule, rule *r if len(statusParams.RequiredStatusChecks) == 0 { return } - enabled := true - base.CheckRules.RequiresStatusChecks = &enabled + base.CheckRules.RequiresStatusChecks = asPtr(true) base.CheckRules.UpToDateBeforeMerge = statusParams.StrictRequiredStatusChecksPolicy for _, chk := range statusParams.RequiredStatusChecks { if chk.Context == nil { @@ -534,14 +558,17 @@ func translateRequiredStatusRepoRule(base *clients.BranchProtectionRule, rule *r } } +// Merge strategy: +// - if both are nil, keep it nil +// - if any of them is not nil, keep the most restrictive one func mergeBranchProtectionRules(base, translated *clients.BranchProtectionRule) { - if base.AllowDeletions == nil || translated.AllowDeletions != nil && !*translated.AllowDeletions { + if base.AllowDeletions == nil || (translated.AllowDeletions != nil && !*translated.AllowDeletions) { base.AllowDeletions = translated.AllowDeletions } - if base.AllowForcePushes == nil || translated.AllowForcePushes != nil && !*translated.AllowForcePushes { + if base.AllowForcePushes == nil || (translated.AllowForcePushes != nil && !*translated.AllowForcePushes) { base.AllowForcePushes = translated.AllowForcePushes } - if base.EnforceAdmins == nil || translated.EnforceAdmins != nil && !*translated.EnforceAdmins { + if base.EnforceAdmins == nil || (translated.EnforceAdmins != nil && !*translated.EnforceAdmins) { // this is an over simplification to get preliminary support for repo rules merged. // A more complete approach would process all rules without bypass actors first, // then process those with bypass actors. If no settings improve (due to rule layering), @@ -549,21 +576,21 @@ func mergeBranchProtectionRules(base, translated *clients.BranchProtectionRule) // https://github.com/ossf/scorecard/issues/3480 base.EnforceAdmins = translated.EnforceAdmins } - if base.RequireLastPushApproval == nil || readBoolPtr(translated.RequireLastPushApproval) { + if base.RequireLastPushApproval == nil || valueOrZero(translated.RequireLastPushApproval) { base.RequireLastPushApproval = translated.RequireLastPushApproval } - if base.RequireLinearHistory == nil || readBoolPtr(translated.RequireLinearHistory) { + if base.RequireLinearHistory == nil || valueOrZero(translated.RequireLinearHistory) { base.RequireLinearHistory = translated.RequireLinearHistory } - mergePullRequestReviews(&base.RequiredPullRequestReviews, &translated.RequiredPullRequestReviews) mergeCheckRules(&base.CheckRules, &translated.CheckRules) + mergePullRequestReviews(&base.RequiredPullRequestReviews, translated.RequiredPullRequestReviews) } func mergeCheckRules(base, translated *clients.StatusChecksRule) { - if base.UpToDateBeforeMerge == nil || readBoolPtr(translated.UpToDateBeforeMerge) { + if base.UpToDateBeforeMerge == nil || valueOrZero(translated.UpToDateBeforeMerge) { base.UpToDateBeforeMerge = translated.UpToDateBeforeMerge } - if base.RequiresStatusChecks == nil || readBoolPtr(translated.RequiresStatusChecks) { + if base.RequiresStatusChecks == nil || valueOrZero(translated.RequiresStatusChecks) { base.RequiresStatusChecks = translated.RequiresStatusChecks } for _, context := range translated.Contexts { @@ -574,28 +601,39 @@ func mergeCheckRules(base, translated *clients.StatusChecksRule) { } } -func mergePullRequestReviews(base, translated *clients.PullRequestReviewRule) { - if readIntPtr(translated.RequiredApprovingReviewCount) > readIntPtr(base.RequiredApprovingReviewCount) { - base.RequiredApprovingReviewCount = translated.RequiredApprovingReviewCount +func mergePullRequestReviews(base **clients.PullRequestReviewRule, translated *clients.PullRequestReviewRule) { + switch { + case translated == nil: + // "translated" have nothing to be merged in base + return + case *base == nil: + // result would be "translated" itself + *base = translated + return } - if base.DismissStaleReviews == nil || readBoolPtr(translated.DismissStaleReviews) { - base.DismissStaleReviews = translated.DismissStaleReviews + + if (*base).RequiredApprovingReviewCount == nil || + valueOrZero((*base).RequiredApprovingReviewCount) < valueOrZero(translated.RequiredApprovingReviewCount) { + (*base).RequiredApprovingReviewCount = translated.RequiredApprovingReviewCount + } + if (*base).DismissStaleReviews == nil || valueOrZero(translated.DismissStaleReviews) { + (*base).DismissStaleReviews = translated.DismissStaleReviews } - if base.RequireCodeOwnerReviews == nil || readBoolPtr(translated.RequireCodeOwnerReviews) { - base.RequireCodeOwnerReviews = translated.RequireCodeOwnerReviews + if (*base).RequireCodeOwnerReviews == nil || valueOrZero(translated.RequireCodeOwnerReviews) { + (*base).RequireCodeOwnerReviews = translated.RequireCodeOwnerReviews } } -func readBoolPtr(b *bool) bool { - if b == nil { - return false - } - return *b +// returns a pointer to the given value. Useful for constant values. +func asPtr[T any](value T) *T { + return &value } -func readIntPtr(i *int32) int32 { - if i == nil { - return 0 +// returns the pointer's value if it exists, the type's zero-value otherwise. +func valueOrZero[T any](ptr *T) T { + if ptr == nil { + var zero T + return zero } - return *i + return *ptr } diff --git a/clients/githubrepo/branches_test.go b/clients/githubrepo/branches_test.go index 73a9401e141..d54b79ce750 100644 --- a/clients/githubrepo/branches_test.go +++ b/clients/githubrepo/branches_test.go @@ -180,34 +180,68 @@ func Test_applyRepoRules(t *testing.T) { t.Parallel() trueVal := true falseVal := false + zeroVal := int32(0) twoVal := int32(2) testcases := []struct { base *clients.BranchRef - ruleSet *repoRuleSet expected *clients.BranchRef ruleBypass *ruleSetBypass name string + ruleSets []*repoRuleSet }{ { - name: "block deletion no bypass", - base: &clients.BranchRef{}, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleDeletion})), + name: "unchecked checkboxes have consistent values", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(), + }, + expected: &clients.BranchRef{ + BranchProtectionRule: clients.BranchProtectionRule{ + AllowDeletions: &trueVal, + AllowForcePushes: &trueVal, + CheckRules: clients.StatusChecksRule{ + // nil values mean that the CheckRules checkbox wasn't checked + UpToDateBeforeMerge: nil, + RequiresStatusChecks: nil, + Contexts: nil, + }, + EnforceAdmins: &trueVal, + RequireLastPushApproval: nil, // this checkbox is enabled only if require status checks + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: nil, + }, + }, + }, + { + name: "block deletion no bypass", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleDeletion})), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - EnforceAdmins: &trueVal, + AllowDeletions: &falseVal, + AllowForcePushes: &trueVal, + RequireLinearHistory: &falseVal, + EnforceAdmins: &trueVal, + RequiredPullRequestReviews: nil, }, }, }, { - name: "block deletion with bypass", - base: &clients.BranchRef{}, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleDeletion}), withBypass()), + name: "block deletion with bypass", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleDeletion}), withBypass()), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - EnforceAdmins: &falseVal, + AllowDeletions: &falseVal, + AllowForcePushes: &trueVal, + RequireLinearHistory: &falseVal, + EnforceAdmins: &falseVal, + RequiredPullRequestReviews: nil, }, }, }, @@ -219,12 +253,16 @@ func Test_applyRepoRules(t *testing.T) { EnforceAdmins: &trueVal, }, }, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleDeletion}, &repoRule{Type: ruleForcePush}), withBypass()), + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleDeletion}, &repoRule{Type: ruleForcePush}), withBypass()), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &falseVal, // Downgrade: deletion does not enforce admins + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &falseVal, // Downgrade: deletion does not enforce admins + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: nil, }, }, }, @@ -232,16 +270,21 @@ func Test_applyRepoRules(t *testing.T) { name: "block deletion no bypass while force push is blocked with bypass", base: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowForcePushes: &falseVal, - EnforceAdmins: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &falseVal, + RequireLinearHistory: &falseVal, }, }, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleDeletion})), + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleDeletion})), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &falseVal, // Maintain: deletion enforces but forcepush does not + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &falseVal, // Maintain: deletion enforces but forcepush does not + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: nil, }, }, }, @@ -253,57 +296,103 @@ func Test_applyRepoRules(t *testing.T) { EnforceAdmins: &trueVal, }, }, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleDeletion})), + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleDeletion})), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &trueVal, // Maintain: base and rule are equal strictness + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &trueVal, // Maintain: base and rule are equal strictness + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: nil, }, }, }, { - name: "block force push no bypass", - base: &clients.BranchRef{}, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleForcePush})), + name: "block force push no bypass", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleForcePush})), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowForcePushes: &falseVal, - EnforceAdmins: &trueVal, + AllowDeletions: &trueVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &trueVal, + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: nil, }, }, }, { - name: "require linear history no bypass", - base: &clients.BranchRef{}, - ruleSet: ruleSet(withRules(&repoRule{Type: ruleLinear})), + name: "require linear history no bypass", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{Type: ruleLinear})), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - RequireLinearHistory: &trueVal, - EnforceAdmins: &trueVal, + AllowDeletions: &trueVal, + AllowForcePushes: &trueVal, + RequireLinearHistory: &trueVal, + EnforceAdmins: &trueVal, + RequiredPullRequestReviews: nil, }, }, }, { - name: "require pull request no bypass", + name: "require pull request but no reviewers and no bypass", base: &clients.BranchRef{}, - ruleSet: ruleSet(withRules(&repoRule{ - Type: rulePullRequest, - Parameters: repoRulesParameters{ - PullRequestParameters: pullRequestRuleParameters{ - DismissStaleReviewsOnPush: &trueVal, - RequireCodeOwnerReview: &trueVal, - RequireLastPushApproval: &trueVal, - RequiredApprovingReviewCount: &twoVal, - RequiredReviewThreadResolution: &trueVal, + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{ + Type: rulePullRequest, + Parameters: repoRulesParameters{ + PullRequestParameters: pullRequestRuleParameters{ + RequireLastPushApproval: asPtr(true), + RequiredApprovingReviewCount: &zeroVal, + }, + }, + })), + }, + expected: &clients.BranchRef{ + BranchProtectionRule: clients.BranchProtectionRule{ + AllowDeletions: &trueVal, + AllowForcePushes: &trueVal, + EnforceAdmins: &trueVal, + RequireLastPushApproval: &trueVal, + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredApprovingReviewCount: &zeroVal, }, }, - })), + }, + }, + { + name: "require pull request with 2 reviewers no bypass", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{ + Type: rulePullRequest, + Parameters: repoRulesParameters{ + PullRequestParameters: pullRequestRuleParameters{ + DismissStaleReviewsOnPush: &trueVal, + RequireCodeOwnerReview: &trueVal, + RequireLastPushApproval: &trueVal, + RequiredApprovingReviewCount: &twoVal, + RequiredReviewThreadResolution: &trueVal, + }, + }, + })), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ + AllowDeletions: &trueVal, + AllowForcePushes: &trueVal, EnforceAdmins: &trueVal, + RequireLinearHistory: &falseVal, RequireLastPushApproval: &trueVal, - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &twoVal, @@ -314,27 +403,103 @@ func Test_applyRepoRules(t *testing.T) { { name: "required status checks no bypass", base: &clients.BranchRef{}, - ruleSet: ruleSet(withRules(&repoRule{ - Type: ruleStatusCheck, - Parameters: repoRulesParameters{ - StatusCheckParameters: requiredStatusCheckParameters{ - StrictRequiredStatusChecksPolicy: &trueVal, - RequiredStatusChecks: []statusCheck{ - { - Context: stringPtr("foo"), + ruleSets: []*repoRuleSet{ + ruleSet(withRules(&repoRule{ + Type: ruleStatusCheck, + Parameters: repoRulesParameters{ + StatusCheckParameters: requiredStatusCheckParameters{ + StrictRequiredStatusChecksPolicy: &trueVal, + RequiredStatusChecks: []statusCheck{ + { + Context: asPtr("foo"), + }, }, }, }, - }, - })), + })), + }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - EnforceAdmins: &trueVal, + AllowDeletions: &trueVal, + AllowForcePushes: &trueVal, + EnforceAdmins: &trueVal, + RequireLinearHistory: &falseVal, CheckRules: clients.StatusChecksRule{ UpToDateBeforeMerge: &trueVal, RequiresStatusChecks: &trueVal, Contexts: []string{"foo"}, }, + RequiredPullRequestReviews: nil, + }, + }, + }, + { + name: "Multiple rules sets impacting a branch", + base: &clients.BranchRef{}, + ruleSets: []*repoRuleSet{ + ruleSet(withRules( // first a restrictive rule set, let's suppose it was built only for main. + &repoRule{Type: ruleDeletion}, + &repoRule{Type: ruleForcePush}, + &repoRule{Type: ruleLinear}, + &repoRule{ + Type: ruleStatusCheck, + Parameters: repoRulesParameters{ + StatusCheckParameters: requiredStatusCheckParameters{ + StrictRequiredStatusChecksPolicy: &trueVal, + RequiredStatusChecks: []statusCheck{ + { + Context: asPtr("foo"), + }, + }, + }, + }, + }, + &repoRule{ + Type: rulePullRequest, + Parameters: repoRulesParameters{ + PullRequestParameters: pullRequestRuleParameters{ + DismissStaleReviewsOnPush: &trueVal, + RequireCodeOwnerReview: &trueVal, + RequireLastPushApproval: &trueVal, + RequiredApprovingReviewCount: &twoVal, + RequiredReviewThreadResolution: &trueVal, + }, + }, + }, + )), + ruleSet(withRules( // Then a more permissive rule set, that might be applied to a broader range of branches. + &repoRule{Type: ruleDeletion}, + &repoRule{ + Type: rulePullRequest, + Parameters: repoRulesParameters{ + PullRequestParameters: pullRequestRuleParameters{ + DismissStaleReviewsOnPush: &falseVal, + RequireCodeOwnerReview: &falseVal, + RequireLastPushApproval: &falseVal, + RequiredApprovingReviewCount: &zeroVal, + RequiredReviewThreadResolution: &falseVal, + }, + }, + }, + )), + }, + expected: &clients.BranchRef{ // We expect to see dominance of restrictive rules. + BranchProtectionRule: clients.BranchProtectionRule{ + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &trueVal, + RequireLinearHistory: &trueVal, + RequireLastPushApproval: &trueVal, + CheckRules: clients.StatusChecksRule{ + UpToDateBeforeMerge: &trueVal, + RequiresStatusChecks: &trueVal, + Contexts: []string{"foo"}, + }, + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredApprovingReviewCount: &twoVal, + DismissStaleReviews: &trueVal, + RequireCodeOwnerReviews: &trueVal, + }, }, }, }, @@ -344,7 +509,7 @@ func Test_applyRepoRules(t *testing.T) { testcase := testcase t.Run(testcase.name, func(t *testing.T) { t.Parallel() - applyRepoRules(testcase.base, []*repoRuleSet{testcase.ruleSet}) + applyRepoRules(testcase.base, testcase.ruleSets) if !cmp.Equal(testcase.base, testcase.expected) { diff := cmp.Diff(testcase.base, testcase.expected) @@ -354,6 +519,102 @@ func Test_applyRepoRules(t *testing.T) { } } -func stringPtr(s string) *string { - return &s +func Test_translationFromGithubAPIBranchProtectionData(t *testing.T) { + t.Parallel() + trueVal := true + falseVal := false + zeroVal := int32(0) + + testcases := []struct { + branch *branch + ruleSet *repoRuleSet + expected *clients.BranchRef + name string + }{ + { + name: "Non-admin Branch Protection rule with insufficient data about requiring PRs", + branch: &branch{ + RefUpdateRule: &refUpdateRule{ + AllowsDeletions: &falseVal, + AllowsForcePushes: &falseVal, + RequiredApprovingReviewCount: &zeroVal, + RequiresCodeOwnerReviews: &falseVal, + RequiresLinearHistory: &falseVal, + RequiredStatusCheckContexts: nil, + }, + BranchProtectionRule: nil, + }, + ruleSet: nil, + expected: &clients.BranchRef{ + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + RequireLinearHistory: &falseVal, + CheckRules: clients.StatusChecksRule{ + UpToDateBeforeMerge: nil, + RequiresStatusChecks: nil, + Contexts: []string{}, + }, + RequiredPullRequestReviews: nil, + }, + }, + }, + { + name: "Admin Branch Protection rule nothing selected", + branch: &branch{ + BranchProtectionRule: &branchProtectionRule{ + DismissesStaleReviews: &falseVal, + IsAdminEnforced: &falseVal, + RequiresStrictStatusChecks: &falseVal, + RequiresStatusChecks: &falseVal, + AllowsDeletions: &falseVal, + AllowsForcePushes: &falseVal, + RequiredApprovingReviewCount: nil, + RequiresCodeOwnerReviews: &falseVal, + RequiresLinearHistory: &falseVal, + RequireLastPushApproval: &falseVal, + RequiredStatusCheckContexts: []string{}, + }, + }, + ruleSet: nil, + expected: &clients.BranchRef{ + Protected: &trueVal, + BranchProtectionRule: clients.BranchProtectionRule{ + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &falseVal, + RequireLastPushApproval: &falseVal, + RequireLinearHistory: &falseVal, + CheckRules: clients.StatusChecksRule{ + UpToDateBeforeMerge: &falseVal, + RequiresStatusChecks: &falseVal, + Contexts: []string{}, + }, + RequiredPullRequestReviews: nil, + }, + }, + }, + } + + for _, testcase := range testcases { + testcase := testcase + t.Run(testcase.name, func(t *testing.T) { + t.Parallel() + + var repoRules []*repoRuleSet + if testcase.ruleSet == nil { + repoRules = []*repoRuleSet{} + } else { + repoRules = []*repoRuleSet{testcase.ruleSet} + } + + result := getBranchRefFrom(testcase.branch, repoRules) + + if !cmp.Equal(result, testcase.expected) { + diff := cmp.Diff(result, testcase.expected) + t.Errorf("test failed: expected - %v, got - %v. \n%s", testcase.expected, result, diff) + } + }) + } } diff --git a/clients/gitlabrepo/branches.go b/clients/gitlabrepo/branches.go index 3cfb561545f..bd69d7e613e 100644 --- a/clients/gitlabrepo/branches.go +++ b/clients/gitlabrepo/branches.go @@ -193,7 +193,7 @@ func makeBranchRefFrom(branch *gitlab.Branch, protectedBranch *gitlab.ProtectedB Contexts: makeContextsFromResp(projectStatusChecks), } - pullRequestReviewRule := clients.PullRequestReviewRule{ + pullRequestReviewRule := &clients.PullRequestReviewRule{ DismissStaleReviews: newTrue(), RequireCodeOwnerReviews: &protectedBranch.CodeOwnerApprovalRequired, } diff --git a/cron/internal/format/json_raw_results.go b/cron/internal/format/json_raw_results.go index 1a2d6e64331..9c19227c31e 100644 --- a/cron/internal/format/json_raw_results.go +++ b/cron/internal/format/json_raw_results.go @@ -210,15 +210,17 @@ func addBranchProtectionRawResults(r *jsonScorecardRawResult, bp *checker.Branch bp = &jsonBranchProtectionSettings{ AllowsDeletions: v.BranchProtectionRule.AllowDeletions, AllowsForcePushes: v.BranchProtectionRule.AllowForcePushes, - RequiresCodeOwnerReviews: v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews, RequiresLinearHistory: v.BranchProtectionRule.RequireLinearHistory, - DismissesStaleReviews: v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews, EnforcesAdmins: v.BranchProtectionRule.EnforceAdmins, RequiresStatusChecks: v.BranchProtectionRule.CheckRules.RequiresStatusChecks, RequiresUpToDateBranchBeforeMerging: v.BranchProtectionRule.CheckRules.UpToDateBeforeMerge, - RequiredApprovingReviewCount: v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, StatusCheckContexts: v.BranchProtectionRule.CheckRules.Contexts, } + if v.BranchProtectionRule.RequiredPullRequestReviews != nil { + bp.DismissesStaleReviews = v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews + bp.RequiredApprovingReviewCount = v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount + bp.RequiresCodeOwnerReviews = v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews + } } r.Results.BranchProtections = append(r.Results.BranchProtections, jsonBranchProtection{ Name: *v.Name, diff --git a/docs/checks.md b/docs/checks.md index 8d049df23ed..402544fbded 100644 --- a/docs/checks.md +++ b/docs/checks.md @@ -111,7 +111,8 @@ Tier 1 Requirements (3/10 points): - Prevent branch deletion Tier 2 Requirements (6/10 points): - - Require at least 1 reviewer for approval before merging + - Require at least 1 reviewer for approval before merging (for administrators, this requirement weights twice than the others in this tier) + - For administrators: Require PRs prior to make any code changes - For administrators: Require branch to be up to date before merging - For administrators: Require approval of the most recent reviewable push diff --git a/docs/checks/internal/checks.yaml b/docs/checks/internal/checks.yaml index 7dabefcc5e8..889589c0c58 100644 --- a/docs/checks/internal/checks.yaml +++ b/docs/checks/internal/checks.yaml @@ -199,7 +199,8 @@ checks: - Prevent branch deletion Tier 2 Requirements (6/10 points): - - Require at least 1 reviewer for approval before merging + - Require at least 1 reviewer for approval before merging (for administrators, this requirement weights twice than the others in this tier) + - For administrators: Require PRs prior to make any code changes - For administrators: Require branch to be up to date before merging - For administrators: Require approval of the most recent reviewable push diff --git a/e2e/branch_protection_test.go b/e2e/branch_protection_test.go index 114412d1158..29a547157c3 100644 --- a/e2e/branch_protection_test.go +++ b/e2e/branch_protection_test.go @@ -48,7 +48,7 @@ var _ = Describe("E2E TEST PAT:"+checks.CheckBranchProtection, func() { Error: nil, Score: 6, NumberOfWarn: 2, - NumberOfInfo: 4, + NumberOfInfo: 5, NumberOfDebug: 4, } result := checks.BranchProtection(&req) @@ -106,7 +106,7 @@ var _ = Describe("E2E TEST PAT:"+checks.CheckBranchProtection, func() { Error: nil, Score: 1, NumberOfWarn: 3, - NumberOfInfo: 3, + NumberOfInfo: 4, NumberOfDebug: 4, } result := checks.BranchProtection(&req) @@ -163,9 +163,9 @@ var _ = Describe("E2E TEST:"+checks.CheckBranchProtection+" (repo rules)", func( expected := scut.TestReturn{ Error: nil, Score: 3, - NumberOfWarn: 2, - NumberOfInfo: 4, - NumberOfDebug: 2, + NumberOfWarn: 4, + NumberOfInfo: 5, + NumberOfDebug: 1, } result := checks.BranchProtection(&req) Expect(result.Error).Should(BeNil()) diff --git a/pkg/json_raw_results.go b/pkg/json_raw_results.go index 5d63cacfec8..7f2ef29d135 100644 --- a/pkg/json_raw_results.go +++ b/pkg/json_raw_results.go @@ -712,15 +712,17 @@ func (r *jsonScorecardRawResult) addBranchProtectionRawResults(bp *checker.Branc bp = &jsonBranchProtectionSettings{ AllowsDeletions: v.BranchProtectionRule.AllowDeletions, AllowsForcePushes: v.BranchProtectionRule.AllowForcePushes, - RequiresCodeOwnerReviews: v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews, RequiresLinearHistory: v.BranchProtectionRule.RequireLinearHistory, - DismissesStaleReviews: v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews, EnforcesAdmins: v.BranchProtectionRule.EnforceAdmins, RequiresStatusChecks: v.BranchProtectionRule.CheckRules.RequiresStatusChecks, RequiresUpToDateBranchBeforeMerging: v.BranchProtectionRule.CheckRules.UpToDateBeforeMerge, - RequiredApprovingReviewCount: v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, StatusCheckContexts: v.BranchProtectionRule.CheckRules.Contexts, } + if v.BranchProtectionRule.RequiredPullRequestReviews != nil { + bp.DismissesStaleReviews = v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews + bp.RequiredApprovingReviewCount = v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount + bp.RequiresCodeOwnerReviews = v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews + } } branches = append(branches, jsonBranchProtection{ Name: *v.Name, diff --git a/pkg/json_raw_results_test.go b/pkg/json_raw_results_test.go index d9391c8c55e..098d6dfc974 100644 --- a/pkg/json_raw_results_test.go +++ b/pkg/json_raw_results_test.go @@ -1114,7 +1114,7 @@ func TestJsonScorecardRawResult(t *testing.T) { BranchProtectionRule: clients.BranchProtectionRule{ AllowDeletions: boolPtr(true), AllowForcePushes: boolPtr(false), - RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredPullRequestReviews: &clients.PullRequestReviewRule{ RequireCodeOwnerReviews: boolPtr(true), DismissStaleReviews: boolPtr(true), RequiredApprovingReviewCount: intPtr(2), From 3ce1daa74a3285bb94448c7b15fef2ffb997bc1e Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 12 Dec 2023 17:38:50 +0000 Subject: [PATCH 42/51] :seedling: Add probes to main call (#3688) * :seedling: Add probes to main call Signed-off-by: AdamKorcz * fix linter issues Signed-off-by: AdamKorcz * add test Signed-off-by: AdamKorcz * add test coverage Signed-off-by: AdamKorcz * remove Signed-off-by: Adam Korczynski * WIP Signed-off-by: Adam Korczynski * change comment for 'ExperimentalRunProbes' Signed-off-by: Adam Korczynski * fix linter issues Signed-off-by: Adam Korczynski * make only one in root.go Signed-off-by: Adam Korczynski * relocate printing of output Signed-off-by: Adam Korczynski * remove FormatPJSON Signed-off-by: Adam Korczynski * reduce complexity of rootCmd Signed-off-by: Adam Korczynski * assign findings in runEnabledProbes Signed-off-by: Adam Korczynski * change name of probe map Signed-off-by: Adam Korczynski * unwrap error Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- cmd/root.go | 45 +++++++++++-- options/flags.go | 9 +++ options/options.go | 5 ++ pkg/scorecard.go | 123 +++++++++++++++++++++++++++++------ pkg/scorecard_result.go | 108 +++++++++++++++++++++++++++++-- pkg/scorecard_test.go | 139 ++++++++++++++++++++++++++++++++++++++++ probes/entries.go | 85 ++++++++++++++++++++++++ 7 files changed, 486 insertions(+), 28 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 506cdb819ed..b66272c0bca 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -73,6 +73,9 @@ func New(o *options.Options) *cobra.Command { // rootCmd runs scorecard checks given a set of arguments. func rootCmd(o *options.Options) error { + var err error + var repoResult pkg.ScorecardResult + p := &pmc.PackageManagerClient{} // Set `repo` from package managers. pkgResp, err := fetchGitRepositoryFromPackageManagers(o.NPM, o.PyPI, o.RubyGems, o.Nuget, p) @@ -119,18 +122,22 @@ func rootCmd(o *options.Options) error { return fmt.Errorf("GetEnabled: %w", err) } + enabledProbes := o.Probes() if o.Format == options.FormatDefault { - for checkName := range enabledChecks { - fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName) + if len(enabledProbes) > 0 { + printProbeStart(enabledProbes) + } else { + printCheckStart(enabledChecks) } } - repoResult, err := pkg.RunScorecard( + repoResult, err = pkg.ExperimentalRunProbes( ctx, repoURI, o.Commit, o.CommitDepth, enabledChecks, + enabledProbes, repoClient, ossFuzzRepoClient, ciiClient, @@ -148,10 +155,11 @@ func rootCmd(o *options.Options) error { }) if o.Format == options.FormatDefault { - for checkName := range enabledChecks { - fmt.Fprintf(os.Stderr, "Finished [%s]\n", checkName) + if len(enabledProbes) > 0 { + printProbeResults(enabledProbes) + } else { + printCheckResults(enabledChecks) } - fmt.Fprintln(os.Stderr, "\nRESULTS\n-------") } resultsErr := pkg.FormatResults( @@ -172,3 +180,28 @@ func rootCmd(o *options.Options) error { } return nil } + +func printProbeStart(enabledProbes []string) { + for _, probeName := range enabledProbes { + fmt.Fprintf(os.Stderr, "Starting probe [%s]\n", probeName) + } +} + +func printCheckStart(enabledChecks checker.CheckNameToFnMap) { + for checkName := range enabledChecks { + fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName) + } +} + +func printProbeResults(enabledProbes []string) { + for _, probeName := range enabledProbes { + fmt.Fprintf(os.Stderr, "Finished probe %s\n", probeName) + } +} + +func printCheckResults(enabledChecks checker.CheckNameToFnMap) { + for checkName := range enabledChecks { + fmt.Fprintf(os.Stderr, "Finished [%s]\n", checkName) + } + fmt.Fprintln(os.Stderr, "\nRESULTS\n-------") +} diff --git a/options/flags.go b/options/flags.go index 2691c4a1978..cf512c033b6 100644 --- a/options/flags.go +++ b/options/flags.go @@ -70,6 +70,8 @@ const ( ShorthandFlagResultsFile = "o" FlagCommitDepth = "commit-depth" + + FlagProbes = "probes" ) // Command is an interface for handling options for command-line utilities. @@ -168,6 +170,13 @@ func (o *Options) AddFlags(cmd *cobra.Command) { fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")), ) + cmd.Flags().StringSliceVar( + &o.ProbesToRun, + FlagProbes, + o.ProbesToRun, + "Probes to run.", + ) + // TODO(options): Extract logic allowedFormats := []string{ FormatDefault, diff --git a/options/options.go b/options/options.go index 30acfe0efe3..2d328735051 100644 --- a/options/options.go +++ b/options/options.go @@ -42,6 +42,7 @@ type Options struct { PolicyFile string ResultsFile string ChecksToRun []string + ProbesToRun []string Metadata []string CommitDepth int ShowDetails bool @@ -240,6 +241,10 @@ func (o *Options) Checks() []string { return o.ChecksToRun } +func (o *Options) Probes() []string { + return o.ProbesToRun +} + // isExperimentalEnabled returns true if experimental features were enabled via // environment variable. func (o *Options) isExperimentalEnabled() bool { diff --git a/pkg/scorecard.go b/pkg/scorecard.go index b8c1a4e1691..321806c3ada 100644 --- a/pkg/scorecard.go +++ b/pkg/scorecard.go @@ -39,20 +39,11 @@ import ( var errEmptyRepository = errors.New("repository empty") func runEnabledChecks(ctx context.Context, - repo clients.Repo, raw *checker.RawResults, checksToRun checker.CheckNameToFnMap, - repoClient clients.RepoClient, ossFuzzRepoClient clients.RepoClient, ciiClient clients.CIIBestPracticesClient, - vulnsClient clients.VulnerabilitiesClient, + repo clients.Repo, + request *checker.CheckRequest, + checksToRun checker.CheckNameToFnMap, resultsCh chan checker.CheckResult, ) { - request := checker.CheckRequest{ - Ctx: ctx, - RepoClient: repoClient, - OssFuzzRepo: ossFuzzRepoClient, - CIIClient: ciiClient, - VulnerabilitiesClient: vulnsClient, - Repo: repo, - RawResults: raw, - } wg := sync.WaitGroup{} for checkName, checkFn := range checksToRun { checkName := checkName @@ -63,7 +54,7 @@ func runEnabledChecks(ctx context.Context, runner := checker.NewRunner( checkName, repo.URI(), - &request, + request, ) resultsCh <- runner.Run(ctx, checkFn) @@ -89,12 +80,12 @@ func getRepoCommitHash(r clients.RepoClient) (string, error) { return commits[0].SHA, nil } -// RunScorecard runs enabled Scorecard checks on a Repo. -func RunScorecard(ctx context.Context, +func runScorecard(ctx context.Context, repo clients.Repo, commitSHA string, commitDepth int, checksToRun checker.CheckNameToFnMap, + probesToRun []string, repoClient clients.RepoClient, ossFuzzRepoClient clients.RepoClient, ciiClient clients.CIIBestPracticesClient, @@ -150,9 +141,27 @@ func RunScorecard(ctx context.Context, "repository.defaultBranch": defaultBranch, } - go runEnabledChecks(ctx, repo, &ret.RawResults, checksToRun, - repoClient, ossFuzzRepoClient, - ciiClient, vulnsClient, resultsCh) + request := &checker.CheckRequest{ + Ctx: ctx, + RepoClient: repoClient, + OssFuzzRepo: ossFuzzRepoClient, + CIIClient: ciiClient, + VulnerabilitiesClient: vulnsClient, + Repo: repo, + RawResults: &ret.RawResults, + } + + // If the user runs probes + if len(probesToRun) > 0 { + err = runEnabledProbes(request, probesToRun, &ret) + if err != nil { + return ScorecardResult{}, err + } + return ret, nil + } + + // If the user runs checks + go runEnabledChecks(ctx, repo, request, checksToRun, resultsCh) for result := range resultsCh { ret.Checks = append(ret.Checks, result) @@ -176,3 +185,81 @@ func RunScorecard(ctx context.Context, } return ret, nil } + +func runEnabledProbes(request *checker.CheckRequest, + probesToRun []string, + ret *ScorecardResult, +) error { + // Add RawResults to request + err := populateRawResults(request, probesToRun, ret) + if err != nil { + return err + } + + probeFindings := make([]finding.Finding, 0) + for _, probeName := range probesToRun { + // Get the probe Run func + probeRunner, err := probes.GetProbeRunner(probeName) + if err != nil { + msg := fmt.Sprintf("could not find probe: %s", probeName) + return sce.WithMessage(sce.ErrScorecardInternal, msg) + } + // Run probe + findings, _, err := probeRunner(&ret.RawResults) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, "ending run") + } + probeFindings = append(probeFindings, findings...) + } + ret.Findings = probeFindings + return nil +} + +// RunScorecard runs enabled Scorecard checks on a Repo. +func RunScorecard(ctx context.Context, + repo clients.Repo, + commitSHA string, + commitDepth int, + checksToRun checker.CheckNameToFnMap, + repoClient clients.RepoClient, + ossFuzzRepoClient clients.RepoClient, + ciiClient clients.CIIBestPracticesClient, + vulnsClient clients.VulnerabilitiesClient, +) (ScorecardResult, error) { + return runScorecard(ctx, + repo, + commitSHA, + commitDepth, + checksToRun, + []string{}, + repoClient, + ossFuzzRepoClient, + ciiClient, + vulnsClient, + ) +} + +// ExperimentalRunProbes is experimental. Do not depend on it, it may be removed at any point. +func ExperimentalRunProbes(ctx context.Context, + repo clients.Repo, + commitSHA string, + commitDepth int, + checksToRun checker.CheckNameToFnMap, + probesToRun []string, + repoClient clients.RepoClient, + ossFuzzRepoClient clients.RepoClient, + ciiClient clients.CIIBestPracticesClient, + vulnsClient clients.VulnerabilitiesClient, +) (ScorecardResult, error) { + return runScorecard(ctx, + repo, + commitSHA, + commitDepth, + checksToRun, + probesToRun, + repoClient, + ossFuzzRepoClient, + ciiClient, + vulnsClient, + ) +} diff --git a/pkg/scorecard_result.go b/pkg/scorecard_result.go index ed06013b897..102f4e3ec0a 100644 --- a/pkg/scorecard_result.go +++ b/pkg/scorecard_result.go @@ -23,12 +23,19 @@ import ( "github.com/olekukonko/tablewriter" "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/docs/checks" + "github.com/ossf/scorecard/v4/checks" + "github.com/ossf/scorecard/v4/checks/raw" + "github.com/ossf/scorecard/v4/checks/raw/github" + "github.com/ossf/scorecard/v4/checks/raw/gitlab" + "github.com/ossf/scorecard/v4/clients/githubrepo" + "github.com/ossf/scorecard/v4/clients/gitlabrepo" + docChecks "github.com/ossf/scorecard/v4/docs/checks" sce "github.com/ossf/scorecard/v4/errors" "github.com/ossf/scorecard/v4/finding" "github.com/ossf/scorecard/v4/log" "github.com/ossf/scorecard/v4/options" spol "github.com/ossf/scorecard/v4/policy" + "github.com/ossf/scorecard/v4/probes" ) // ScorecardInfo contains information about the scorecard code that was run. @@ -62,7 +69,7 @@ func scoreToString(s float64) string { } // GetAggregateScore returns the aggregate score. -func (r *ScorecardResult) GetAggregateScore(checkDocs checks.Doc) (float64, error) { +func (r *ScorecardResult) GetAggregateScore(checkDocs docChecks.Doc) (float64, error) { // TODO: calculate the score and make it a field // of ScorecardResult weights := map[string]float64{"Critical": 10, "High": 7.5, "Medium": 5, "Low": 2.5} @@ -105,7 +112,7 @@ func (r *ScorecardResult) GetAggregateScore(checkDocs checks.Doc) (float64, erro func FormatResults( opts *options.Options, results *ScorecardResult, - doc checks.Doc, + doc docChecks.Doc, policy *spol.ScorecardPolicy, ) error { var err error @@ -153,7 +160,7 @@ func FormatResults( // AsString returns ScorecardResult in string format. func (r *ScorecardResult) AsString(showDetails bool, logLevel log.Level, - checkDocs checks.Doc, writer io.Writer, + checkDocs docChecks.Doc, writer io.Writer, ) error { data := make([][]string, len(r.Checks)) @@ -225,3 +232,96 @@ func (r *ScorecardResult) AsString(showDetails bool, logLevel log.Level, return nil } + +func assignRawData(probeCheckName string, request *checker.CheckRequest, ret *ScorecardResult) error { + switch probeCheckName { + case checks.CheckSecurityPolicy: + rawData, err := raw.SecurityPolicy(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.SecurityPolicyResults = rawData + case checks.CheckDependencyUpdateTool: + rawData, err := raw.DependencyUpdateTool(request.RepoClient) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.DependencyUpdateToolResults = rawData + case checks.CheckFuzzing: + rawData, err := raw.Fuzzing(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.FuzzingResults = rawData + case checks.CheckPackaging: + switch request.RepoClient.(type) { + case *githubrepo.Client: + rawData, err := github.Packaging(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.PackagingResults = rawData + case *gitlabrepo.Client: + rawData, err := gitlab.Packaging(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.PackagingResults = rawData + default: + return sce.WithMessage(sce.ErrScorecardInternal, + "Only github and gitlab are supported") + } + case checks.CheckLicense: + rawData, err := raw.License(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.LicenseResults = rawData + case checks.CheckContributors: + rawData, err := raw.Contributors(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.ContributorsResults = rawData + case checks.CheckVulnerabilities: + rawData, err := raw.Vulnerabilities(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.VulnerabilitiesResults = rawData + case checks.CheckSAST: + rawData, err := raw.SAST(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.SASTResults = rawData + case checks.CheckDangerousWorkflow: + rawData, err := raw.DangerousWorkflow(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.DangerousWorkflowResults = rawData + case checks.CheckMaintained: + rawData, err := raw.Maintained(request) + if err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } + ret.RawResults.MaintainedResults = rawData + } + return nil +} + +func populateRawResults(request *checker.CheckRequest, probesToRun []string, ret *ScorecardResult) error { + probeCheckNames := make([]string, 0) + for _, probeName := range probesToRun { + probeCheckName := probes.CheckMap[probeName] + if !contains(probeCheckNames, probeCheckName) { + probeCheckNames = append(probeCheckNames, probeCheckName) + err := assignRawData(probeCheckName, request, ret) + if err != nil { + return err + } + } + } + return nil +} diff --git a/pkg/scorecard_test.go b/pkg/scorecard_test.go index 76a4ced138b..32295b21275 100644 --- a/pkg/scorecard_test.go +++ b/pkg/scorecard_test.go @@ -21,9 +21,12 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/ossf/scorecard/v4/checker" "github.com/ossf/scorecard/v4/clients" "github.com/ossf/scorecard/v4/clients/localdir" mockrepo "github.com/ossf/scorecard/v4/clients/mockclients" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/finding/probe" "github.com/ossf/scorecard/v4/log" ) @@ -187,3 +190,139 @@ func TestRunScorecard(t *testing.T) { }) } } + +func TestExperimentalRunProbes(t *testing.T) { + t.Parallel() + type args struct { + uri string + commitSHA string + probes []string + } + tests := []struct { + files []string + name string + args args + want ScorecardResult + wantErr bool + }{ + { + name: "empty commits repos should return repo details but no checks", + args: args{ + uri: "github.com/ossf/scorecard", + commitSHA: "1a17bb812fb2ac23e9d09e86e122f8b67563aed7", + probes: []string{"fuzzedWithOSSFuzz"}, + }, + want: ScorecardResult{ + Repo: RepoInfo{ + Name: "github.com/ossf/scorecard", + CommitSHA: "1a17bb812fb2ac23e9d09e86e122f8b67563aed7", + }, + RawResults: checker.RawResults{ + Metadata: checker.MetadataData{ + Metadata: map[string]string{ + "repository.defaultBranch": "main", + "repository.host": "github.com", + "repository.name": "ossf/scorecard", + "repository.sha1": "1a17bb812fb2ac23e9d09e86e122f8b67563aed7", + "repository.uri": "github.com/ossf/scorecard", + }, + }, + }, + Scorecard: ScorecardInfo{ + CommitSHA: "unknown", + }, + Findings: []finding.Finding{ + { + Probe: "fuzzedWithOSSFuzz", + Message: "no OSSFuzz integration found", + Remediation: &probe.Remediation{ + Effort: 3, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "Wrong probe", + args: args{ + uri: "github.com/ossf/scorecard", + commitSHA: "1a17bb812fb2ac23e9d09e86e122f8b67563aed7", + probes: []string{"nonExistentProbe"}, + }, + want: ScorecardResult{}, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + ctrl := gomock.NewController(t) + mockRepoClient := mockrepo.NewMockRepoClient(ctrl) + repo := mockrepo.NewMockRepo(ctrl) + + repo.EXPECT().URI().Return(tt.args.uri).AnyTimes() + repo.EXPECT().Host().Return("github.com").AnyTimes() + + mockRepoClient.EXPECT().InitRepo(repo, tt.args.commitSHA, 0).Return(nil) + + mockRepoClient.EXPECT().Close().DoAndReturn(func() error { + return nil + }) + + mockRepoClient.EXPECT().ListCommits().DoAndReturn(func() ([]clients.Commit, error) { + if tt.args.commitSHA == "" { + return []clients.Commit{}, nil + } + return []clients.Commit{ + { + SHA: tt.args.commitSHA, + }, + }, nil + }) + mockRepoClient.EXPECT().ListFiles(gomock.Any()).Return(tt.files, nil).AnyTimes() + progLanguages := []clients.Language{ + { + Name: clients.Go, + NumLines: 100, + }, + { + Name: clients.Java, + NumLines: 70, + }, + { + Name: clients.Cpp, + NumLines: 100, + }, + { + Name: clients.Ruby, + NumLines: 70, + }, + } + mockRepoClient.EXPECT().ListProgrammingLanguages().Return(progLanguages, nil).AnyTimes() + + mockRepoClient.EXPECT().GetDefaultBranchName().Return("main", nil).AnyTimes() + got, err := ExperimentalRunProbes(context.Background(), + repo, + tt.args.commitSHA, + 0, + nil, + tt.args.probes, + mockRepoClient, + nil, + nil, + nil) + if (err != nil) != tt.wantErr { + t.Errorf("RunScorecard() error = %v, wantErr %v", err, tt.wantErr) + return + } + ignoreRemediationText := cmpopts.IgnoreFields(probe.Remediation{}, "Text", "Markdown") + ignoreDate := cmpopts.IgnoreFields(ScorecardResult{}, "Date") + if !cmp.Equal(got, tt.want, ignoreDate, ignoreRemediationText) { + t.Errorf("expected %v, got %v", got, cmp.Diff(tt.want, got, ignoreDate, + ignoreRemediationText)) + } + }) + } +} diff --git a/probes/entries.go b/probes/entries.go index 9f4f8ede19a..6414d224e21 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -15,6 +15,8 @@ package probes import ( + "errors" + "github.com/ossf/scorecard/v4/checker" "github.com/ossf/scorecard/v4/finding" "github.com/ossf/scorecard/v4/probes/contributorsFromOrgOrCompany" @@ -133,6 +135,82 @@ var ( CITests = []ProbeImpl{ testsRunInCI.Run, } + + probeRunners = map[string]func(*checker.RawResults) ([]finding.Finding, string, error){ + securityPolicyPresent.Probe: securityPolicyPresent.Run, + securityPolicyContainsLinks.Probe: securityPolicyContainsLinks.Run, + securityPolicyContainsVulnerabilityDisclosure.Probe: securityPolicyContainsVulnerabilityDisclosure.Run, + securityPolicyContainsText.Probe: securityPolicyContainsText.Run, + toolRenovateInstalled.Probe: toolRenovateInstalled.Run, + toolDependabotInstalled.Probe: toolDependabotInstalled.Run, + toolPyUpInstalled.Probe: toolPyUpInstalled.Run, + fuzzedWithOSSFuzz.Probe: fuzzedWithOSSFuzz.Run, + fuzzedWithGoNative.Probe: fuzzedWithGoNative.Run, + fuzzedWithPythonAtheris.Probe: fuzzedWithPythonAtheris.Run, + fuzzedWithCLibFuzzer.Probe: fuzzedWithCLibFuzzer.Run, + fuzzedWithCppLibFuzzer.Probe: fuzzedWithCppLibFuzzer.Run, + fuzzedWithSwiftLibFuzzer.Probe: fuzzedWithSwiftLibFuzzer.Run, + fuzzedWithRustCargofuzz.Probe: fuzzedWithRustCargofuzz.Run, + fuzzedWithJavaJazzerFuzzer.Probe: fuzzedWithJavaJazzerFuzzer.Run, + fuzzedWithClusterFuzzLite.Probe: fuzzedWithClusterFuzzLite.Run, + fuzzedWithPropertyBasedHaskell.Probe: fuzzedWithPropertyBasedHaskell.Run, + fuzzedWithPropertyBasedTypescript.Probe: fuzzedWithPropertyBasedTypescript.Run, + fuzzedWithPropertyBasedJavascript.Probe: fuzzedWithPropertyBasedJavascript.Run, + packagedWithAutomatedWorkflow.Probe: packagedWithAutomatedWorkflow.Run, + hasLicenseFile.Probe: hasLicenseFile.Run, + hasFSFOrOSIApprovedLicense.Probe: hasFSFOrOSIApprovedLicense.Run, + hasLicenseFileAtTopDir.Probe: hasLicenseFileAtTopDir.Run, + contributorsFromOrgOrCompany.Probe: contributorsFromOrgOrCompany.Run, + hasOSVVulnerabilities.Probe: hasOSVVulnerabilities.Run, + sastToolCodeQLInstalled.Probe: sastToolCodeQLInstalled.Run, + sastToolRunsOnAllCommits.Probe: sastToolRunsOnAllCommits.Run, + sastToolSonarInstalled.Probe: sastToolSonarInstalled.Run, + hasDangerousWorkflowScriptInjection.Probe: hasDangerousWorkflowScriptInjection.Run, + hasDangerousWorkflowUntrustedCheckout.Probe: hasDangerousWorkflowUntrustedCheckout.Run, + notArchived.Probe: notArchived.Run, + hasRecentCommits.Probe: hasRecentCommits.Run, + issueActivityByProjectMember.Probe: issueActivityByProjectMember.Run, + notCreatedRecently.Probe: notCreatedRecently.Run, + } + + CheckMap = map[string]string{ + securityPolicyPresent.Probe: "Security-Policy", + securityPolicyContainsLinks.Probe: "Security-Policy", + securityPolicyContainsVulnerabilityDisclosure.Probe: "Security-Policy", + securityPolicyContainsText.Probe: "Security-Policy", + toolRenovateInstalled.Probe: "Dependency-Update-Tool", + toolDependabotInstalled.Probe: "Dependency-Update-Tool", + toolPyUpInstalled.Probe: "Dependency-Update-Tool", + fuzzedWithOSSFuzz.Probe: "Fuzzing", + fuzzedWithGoNative.Probe: "Fuzzing", + fuzzedWithPythonAtheris.Probe: "Fuzzing", + fuzzedWithCLibFuzzer.Probe: "Fuzzing", + fuzzedWithCppLibFuzzer.Probe: "Fuzzing", + fuzzedWithSwiftLibFuzzer.Probe: "Fuzzing", + fuzzedWithRustCargofuzz.Probe: "Fuzzing", + fuzzedWithJavaJazzerFuzzer.Probe: "Fuzzing", + fuzzedWithClusterFuzzLite.Probe: "Fuzzing", + fuzzedWithPropertyBasedHaskell.Probe: "Fuzzing", + fuzzedWithPropertyBasedTypescript.Probe: "Fuzzing", + fuzzedWithPropertyBasedJavascript.Probe: "Fuzzing", + packagedWithAutomatedWorkflow.Probe: "Packaging", + hasLicenseFile.Probe: "License", + hasFSFOrOSIApprovedLicense.Probe: "License", + hasLicenseFileAtTopDir.Probe: "License", + contributorsFromOrgOrCompany.Probe: "Contributors", + hasOSVVulnerabilities.Probe: "Vulnerabilities", + sastToolCodeQLInstalled.Probe: "SAST", + sastToolRunsOnAllCommits.Probe: "SAST", + sastToolSonarInstalled.Probe: "SAST", + hasDangerousWorkflowScriptInjection.Probe: "Dangerous-Workflow", + hasDangerousWorkflowUntrustedCheckout.Probe: "Dangerous-Workflow", + notArchived.Probe: "Maintained", + hasRecentCommits.Probe: "Maintained", + issueActivityByProjectMember.Probe: "Maintained", + notCreatedRecently.Probe: "Maintained", + } + + errProbeNotFound = errors.New("probe not found") ) //nolint:gochecknoinits @@ -146,6 +224,13 @@ func init() { }) } +func GetProbeRunner(probeName string) (func(*checker.RawResults) ([]finding.Finding, string, error), error) { + if runner, ok := probeRunners[probeName]; ok { + return runner, nil + } + return nil, errProbeNotFound +} + func concatMultipleProbes(slices [][]ProbeImpl) []ProbeImpl { var totalLen int for _, s := range slices { From 663e1a9bad0f62b635cce71af8a1b3a0dabe7ba1 Mon Sep 17 00:00:00 2001 From: Pedro Kaj Kjellerup Nacht Date: Tue, 12 Dec 2023 16:01:00 -0300 Subject: [PATCH 43/51] =?UTF-8?q?=F0=9F=8C=B1=20Use=20backlog=20and=20"hel?= =?UTF-8?q?p=20wanted"=20labels=20on=20issues/PRs=20to=20keep=20stale-bot?= =?UTF-8?q?=20away=20(#3690)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use "never stale" tag on issues/PRs to keep stale-bot away Signed-off-by: Pedro Kaj Kjellerup Nacht * Replace 'never stale' with 'icebox', 'help wanted' Signed-off-by: Pedro Kaj Kjellerup Nacht * Replace "icebox,help needed" with "backlog,help wanted" Signed-off-by: Pedro Kaj Kjellerup Nacht --------- Signed-off-by: Pedro Kaj Kjellerup Nacht --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 974bfed6c9f..7d81d39ed12 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -36,7 +36,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is stale because it has been open for 60 days with no activity.' stale-pr-message: 'This pull request is stale because it has been open for 10 days with no activity' - exempt-issue-labels: 'priority,bug,good first issue' + exempt-issue-labels: 'priority,bug,good first issue,backlog,help wanted' exempt-issue-milestones: 'Structured results' exempt-pr-labels: 'awaiting-approval,work-in-progress' days-before-pr-stale: '10' From d03c8cbb4356ef0bb4d2458181b013b0068e3936 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Tue, 12 Dec 2023 16:26:35 -0800 Subject: [PATCH 44/51] :bug: revert making RequiredPullRequestReviews a pointer (#3728) * revert the change which made RequiredPullRequestReviews a pointer While the current approach works with the tiered scoring, it wont work for probes or if we remove tiers. Making the struct nil to signal that PRs aren't required hides some of the data we do have. This is especially problematic for repo rules, where we can infer all settings by what we see or dont see. Signed-off-by: Spencer Schrock * add helper to deref pointers Signed-off-by: Spencer Schrock * clarify comments and keep code consistent Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- checks/branch_protection_test.go | 27 +++-- checks/evaluation/branch_protection.go | 42 ++++--- checks/evaluation/branch_protection_test.go | 61 ++++++---- clients/branch.go | 7 +- clients/githubrepo/branches.go | 82 ++++++-------- clients/githubrepo/branches_test.go | 119 ++++++++++++-------- clients/gitlabrepo/branches.go | 3 +- cron/internal/format/json_raw_results.go | 8 +- pkg/json_raw_results.go | 8 +- pkg/json_raw_results_test.go | 3 +- 10 files changed, 200 insertions(+), 160 deletions(-) diff --git a/checks/branch_protection_test.go b/checks/branch_protection_test.go index 69c0ddd35ff..9b5810399ae 100644 --- a/checks/branch_protection_test.go +++ b/checks/branch_protection_test.go @@ -93,7 +93,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -112,7 +113,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -151,7 +153,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -186,7 +189,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -207,7 +211,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -242,7 +247,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -263,7 +269,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -299,7 +306,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -337,7 +345,8 @@ func TestReleaseAndDevBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, diff --git a/checks/evaluation/branch_protection.go b/checks/evaluation/branch_protection.go index 21352fb789a..cccf2e28977 100644 --- a/checks/evaluation/branch_protection.go +++ b/checks/evaluation/branch_protection.go @@ -285,9 +285,7 @@ func nonAdminReviewProtection(branch *clients.BranchRef) (int, int) { // Having at least 1 reviewer is twice as important as the other Tier 2 requirements. const reviewerWeight = 2 max += reviewerWeight - if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && - branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount != nil && - *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount > 0 { + if valueOrZero(branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount) > 0 { // We do not display anything here, it's done in nonAdminThoroughReviewProtection() score += reviewerWeight } @@ -329,15 +327,13 @@ func adminReviewProtection(branch *clients.BranchRef, dl checker.DetailLogger) ( } max++ - if branch.BranchProtectionRule.RequiredPullRequestReviews != nil { + if valueOrZero(branch.BranchProtectionRule.RequiredPullRequestReviews.Required) { score++ info(dl, log, "PRs are required in order to make changes on branch '%s'", *branch.Name) } else { warn(dl, log, "PRs are not required to make changes on branch '%s'; or we don't have data to detect it."+ "If you think it might be the latter, make sure to run Scorecard with a PAT or use Repo "+ "Rules (that are always public) instead of Branch Protection settings", *branch.Name) - // Warning it here because since `RequiredPullRequestReviews` is nil, we won't check reviewers count afterwards - warn(dl, log, "No reviewers required to merge changes on branch '%s'", *branch.Name) } return score, max @@ -349,8 +345,7 @@ func adminThoroughReviewProtection(branch *clients.BranchRef, dl checker.DetailL // Only log information if the branch is protected. log := branch.Protected != nil && *branch.Protected - if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && - branch.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews != nil { + if branch.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews != nil { // Note: we don't increase max possible score for non-admin viewers. max++ switch *branch.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews { @@ -391,18 +386,13 @@ func nonAdminThoroughReviewProtection(branch *clients.BranchRef, dl checker.Deta max++ - // On this first check we exclude the case where PRs are not required to make changes, - // because it's already covered on adminReviewProtection function. - if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && - branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount != nil { - if *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount >= minReviews { - info(dl, log, "number of required reviewers is %d on branch '%s'", - *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, *branch.Name) - score++ - } else { - warn(dl, log, "number of required reviewers is %d on branch '%s', while the ideal suggested is %d", - *branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, *branch.Name, minReviews) - } + reviewers := valueOrZero(branch.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount) + if reviewers >= minReviews { + info(dl, log, "number of required reviewers is %d on branch '%s'", reviewers, *branch.Name) + score++ + } else { + warn(dl, log, "number of required reviewers is %d on branch '%s', while the ideal suggested is %d", + reviewers, *branch.Name, minReviews) } return score, max @@ -416,8 +406,7 @@ func codeownerBranchProtection( log := branch.Protected != nil && *branch.Protected - if branch.BranchProtectionRule.RequiredPullRequestReviews != nil && - branch.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews != nil { + if branch.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews != nil { switch *branch.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews { case true: info(dl, log, "codeowner review is required on branch '%s'", *branch.Name) @@ -433,3 +422,12 @@ func codeownerBranchProtection( return score, max } + +// returns the pointer's value if it exists, the type's zero-value otherwise. +func valueOrZero[T any](ptr *T) T { + if ptr == nil { + var zero T + return zero + } + return *ptr +} diff --git a/checks/evaluation/branch_protection_test.go b/checks/evaluation/branch_protection_test.go index db25faf236b..86c34c3e5e6 100644 --- a/checks/evaluation/branch_protection_test.go +++ b/checks/evaluation/branch_protection_test.go @@ -50,7 +50,7 @@ func TestIsBranchProtected(t *testing.T) { expected scut.TestReturn }{ { - name: "Configs as they are right after creating new Branch Protection setting", + name: "GitHub default settings", expected: scut.TestReturn{ Error: nil, Score: 3, @@ -62,12 +62,14 @@ func TestIsBranchProtected(t *testing.T) { Name: &branchVal, Protected: &trueVal, BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - RequireLinearHistory: &falseVal, - EnforceAdmins: &falseVal, - RequireLastPushApproval: &falseVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + RequireLinearHistory: &falseVal, + EnforceAdmins: &falseVal, + RequireLastPushApproval: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, CheckRules: clients.StatusChecksRule{ RequiresStatusChecks: &trueVal, Contexts: nil, @@ -103,7 +105,8 @@ func TestIsBranchProtected(t *testing.T) { Name: &branchVal, Protected: &trueVal, BranchProtectionRule: clients.BranchProtectionRule{ - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -139,7 +142,8 @@ func TestIsBranchProtected(t *testing.T) { RequireLinearHistory: &falseVal, AllowForcePushes: &falseVal, AllowDeletions: &falseVal, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -175,7 +179,9 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: nil, }, - RequiredPullRequestReviews: nil, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -202,7 +208,9 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: nil, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -229,7 +237,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &zeroVal, @@ -260,7 +269,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &oneVal, @@ -291,7 +301,6 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: nil, Contexts: nil, }, - RequiredPullRequestReviews: nil, }, }, }, @@ -318,7 +327,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: nil, Contexts: nil, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: nil, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &oneVal, @@ -349,7 +359,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -380,7 +391,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -412,7 +424,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -443,7 +456,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &falseVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &falseVal, RequireCodeOwnerReviews: &falseVal, RequiredApprovingReviewCount: &zeroVal, @@ -474,7 +488,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -505,7 +520,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, @@ -537,7 +553,8 @@ func TestIsBranchProtected(t *testing.T) { UpToDateBeforeMerge: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &oneVal, diff --git a/clients/branch.go b/clients/branch.go index 4cd6b3d4217..9cabdbc3141 100644 --- a/clients/branch.go +++ b/clients/branch.go @@ -23,11 +23,7 @@ type BranchRef struct { // BranchProtectionRule captures the settings enabled on a branch for security. type BranchProtectionRule struct { - // The nil value of this struct can mean either: - // 1. we can't tell if PRs are required to make changes; or - // 2. we know PRs are not required. The first case happens when Scorecard is run without admin token on - // a repo that uses the old Branch Protection setting (not the new Repo Rules, that are always public). - RequiredPullRequestReviews *PullRequestReviewRule + RequiredPullRequestReviews PullRequestReviewRule AllowDeletions *bool AllowForcePushes *bool RequireLinearHistory *bool @@ -45,6 +41,7 @@ type StatusChecksRule struct { // PullRequestReviewRule captures settings on a PullRequest. type PullRequestReviewRule struct { + Required *bool // are PRs required RequiredApprovingReviewCount *int32 DismissStaleReviews *bool RequireCodeOwnerReviews *bool diff --git a/clients/githubrepo/branches.go b/clients/githubrepo/branches.go index b8ba122ef8e..4c42c07e1fc 100644 --- a/clients/githubrepo/branches.go +++ b/clients/githubrepo/branches.go @@ -327,6 +327,7 @@ func (handler *branchesHandler) getBranch(branch string) (*clients.BranchRef, er func copyAdminSettings(src *branchProtectionRule, dst *clients.BranchProtectionRule) { copyBoolPtr(src.IsAdminEnforced, &dst.EnforceAdmins) copyBoolPtr(src.RequireLastPushApproval, &dst.RequireLastPushApproval) + copyBoolPtr(src.DismissesStaleReviews, &dst.RequiredPullRequestReviews.DismissStaleReviews) if src.RequiresStatusChecks != nil { copyBoolPtr(src.RequiresStatusChecks, &dst.CheckRules.RequiresStatusChecks) // TODO(#3255): Update when GitHub GraphQL bug is fixed @@ -340,14 +341,13 @@ func copyAdminSettings(src *branchProtectionRule, dst *clients.BranchProtectionR copyBoolPtr(&upToDateBeforeMerge, &dst.CheckRules.UpToDateBeforeMerge) } } - - // We're also checking if branch requires PRs because if it doesn't, - // the RequiredPullRequestReviews struct should be nil. - if src.DismissesStaleReviews != nil && branchRequiresPrs(src) { - if dst.RequiredPullRequestReviews == nil { - dst.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) - } - copyBoolPtr(src.DismissesStaleReviews, &dst.RequiredPullRequestReviews.DismissStaleReviews) + // we always have the data to know if PRs are required + if dst.RequiredPullRequestReviews.Required == nil { + dst.RequiredPullRequestReviews.Required = asPtr(false) + } + // these values report as &false when PRs aren't required, so if they're true then PRs are required + if valueOrZero(src.RequireLastPushApproval) || valueOrZero(src.DismissesStaleReviews) { + dst.RequiredPullRequestReviews.Required = asPtr(true) } } @@ -358,39 +358,36 @@ func copyNonAdminSettings(src interface{}, dst *clients.BranchProtectionRule) { copyBoolPtr(v.AllowsDeletions, &dst.AllowDeletions) copyBoolPtr(v.AllowsForcePushes, &dst.AllowForcePushes) copyBoolPtr(v.RequiresLinearHistory, &dst.RequireLinearHistory) + copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) + copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) copyStringSlice(v.RequiredStatusCheckContexts, &dst.CheckRules.Contexts) - // If branch doesn't require PRs to make changes, we let the struct RequiredPullRequestReviews point to nil - if branchRequiresPrs(v) { - if dst.RequiredPullRequestReviews == nil { - dst.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) - } - copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) - copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) + // we always have the data to know if PRs are required + if dst.RequiredPullRequestReviews.Required == nil { + dst.RequiredPullRequestReviews.Required = asPtr(false) + } + // GitHub returns nil for RequiredApprovingReviewCount when PRs aren't required and non-nil when they are + // RequiresCodeOwnerReviews is &false even if PRs aren't required, so we need it to be true + if v.RequiredApprovingReviewCount != nil || valueOrZero(v.RequiresCodeOwnerReviews) { + dst.RequiredPullRequestReviews.Required = asPtr(true) } case *refUpdateRule: copyBoolPtr(v.AllowsDeletions, &dst.AllowDeletions) copyBoolPtr(v.AllowsForcePushes, &dst.AllowForcePushes) copyBoolPtr(v.RequiresLinearHistory, &dst.RequireLinearHistory) + copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) + copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) copyStringSlice(v.RequiredStatusCheckContexts, &dst.CheckRules.Contexts) // Evaluate if we have data to infer that the project requires PRs to make changes. If we don't have data, we let - // the struct RequiredPullRequestReviews as nil + // Required stay nil if valueOrZero(v.RequiredApprovingReviewCount) > 0 || valueOrZero(v.RequiresCodeOwnerReviews) { - if dst.RequiredPullRequestReviews == nil { - dst.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) - } - copyInt32Ptr(v.RequiredApprovingReviewCount, &dst.RequiredPullRequestReviews.RequiredApprovingReviewCount) - copyBoolPtr(v.RequiresCodeOwnerReviews, &dst.RequiredPullRequestReviews.RequireCodeOwnerReviews) + dst.RequiredPullRequestReviews.Required = asPtr(true) } } } -func branchRequiresPrs(data *branchProtectionRule) bool { - return data.RequiredApprovingReviewCount != nil -} - func getDefaultBranchNameFrom(data *ruleSetData) string { if data == nil || data.Repository.DefaultBranchRef.Name == nil { return "" @@ -511,6 +508,9 @@ func applyRepoRules(branchRef *clients.BranchRef, rules []*repoRuleSet) { AllowDeletions: asPtr(true), AllowForcePushes: asPtr(true), RequireLinearHistory: asPtr(false), + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: asPtr(false), + }, } translated.EnforceAdmins = asPtr(len(r.BypassActors.Nodes) == 0) @@ -534,8 +534,7 @@ func applyRepoRules(branchRef *clients.BranchRef, rules []*repoRuleSet) { } func translatePullRequestRepoRule(base *clients.BranchProtectionRule, rule *repoRule) { - base.RequiredPullRequestReviews = new(clients.PullRequestReviewRule) - + base.RequiredPullRequestReviews.Required = asPtr(true) base.RequiredPullRequestReviews.DismissStaleReviews = rule.Parameters.PullRequestParameters.DismissStaleReviewsOnPush base.RequiredPullRequestReviews.RequireCodeOwnerReviews = rule.Parameters.PullRequestParameters.RequireCodeOwnerReview base.RequireLastPushApproval = rule.Parameters.PullRequestParameters.RequireLastPushApproval @@ -583,7 +582,7 @@ func mergeBranchProtectionRules(base, translated *clients.BranchProtectionRule) base.RequireLinearHistory = translated.RequireLinearHistory } mergeCheckRules(&base.CheckRules, &translated.CheckRules) - mergePullRequestReviews(&base.RequiredPullRequestReviews, translated.RequiredPullRequestReviews) + mergePullRequestReviews(&base.RequiredPullRequestReviews, &translated.RequiredPullRequestReviews) } func mergeCheckRules(base, translated *clients.StatusChecksRule) { @@ -601,26 +600,19 @@ func mergeCheckRules(base, translated *clients.StatusChecksRule) { } } -func mergePullRequestReviews(base **clients.PullRequestReviewRule, translated *clients.PullRequestReviewRule) { - switch { - case translated == nil: - // "translated" have nothing to be merged in base - return - case *base == nil: - // result would be "translated" itself - *base = translated - return +func mergePullRequestReviews(base, translated *clients.PullRequestReviewRule) { + if base.Required == nil || valueOrZero(translated.Required) { + base.Required = translated.Required } - - if (*base).RequiredApprovingReviewCount == nil || - valueOrZero((*base).RequiredApprovingReviewCount) < valueOrZero(translated.RequiredApprovingReviewCount) { - (*base).RequiredApprovingReviewCount = translated.RequiredApprovingReviewCount + if base.RequiredApprovingReviewCount == nil || + valueOrZero(base.RequiredApprovingReviewCount) < valueOrZero(translated.RequiredApprovingReviewCount) { + base.RequiredApprovingReviewCount = translated.RequiredApprovingReviewCount } - if (*base).DismissStaleReviews == nil || valueOrZero(translated.DismissStaleReviews) { - (*base).DismissStaleReviews = translated.DismissStaleReviews + if base.DismissStaleReviews == nil || valueOrZero(translated.DismissStaleReviews) { + base.DismissStaleReviews = translated.DismissStaleReviews } - if (*base).RequireCodeOwnerReviews == nil || valueOrZero(translated.RequireCodeOwnerReviews) { - (*base).RequireCodeOwnerReviews = translated.RequireCodeOwnerReviews + if base.RequireCodeOwnerReviews == nil || valueOrZero(translated.RequireCodeOwnerReviews) { + base.RequireCodeOwnerReviews = translated.RequireCodeOwnerReviews } } diff --git a/clients/githubrepo/branches_test.go b/clients/githubrepo/branches_test.go index d54b79ce750..e8467422449 100644 --- a/clients/githubrepo/branches_test.go +++ b/clients/githubrepo/branches_test.go @@ -206,10 +206,12 @@ func Test_applyRepoRules(t *testing.T) { RequiresStatusChecks: nil, Contexts: nil, }, - EnforceAdmins: &trueVal, - RequireLastPushApproval: nil, // this checkbox is enabled only if require status checks - RequireLinearHistory: &falseVal, - RequiredPullRequestReviews: nil, + EnforceAdmins: &trueVal, + RequireLastPushApproval: nil, // this checkbox is enabled only if require status checks + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -221,11 +223,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &trueVal, - RequireLinearHistory: &falseVal, - EnforceAdmins: &trueVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &falseVal, + AllowForcePushes: &trueVal, + RequireLinearHistory: &falseVal, + EnforceAdmins: &trueVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -237,11 +241,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &trueVal, - RequireLinearHistory: &falseVal, - EnforceAdmins: &falseVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &falseVal, + AllowForcePushes: &trueVal, + RequireLinearHistory: &falseVal, + EnforceAdmins: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -258,11 +264,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &falseVal, // Downgrade: deletion does not enforce admins - RequireLinearHistory: &falseVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &falseVal, // Downgrade: deletion does not enforce admins + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -280,11 +288,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &falseVal, // Maintain: deletion enforces but forcepush does not - RequireLinearHistory: &falseVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &falseVal, // Maintain: deletion enforces but forcepush does not + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -301,11 +311,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &falseVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &trueVal, // Maintain: base and rule are equal strictness - RequireLinearHistory: &falseVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &falseVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &trueVal, // Maintain: base and rule are equal strictness + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -317,11 +329,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &trueVal, - AllowForcePushes: &falseVal, - EnforceAdmins: &trueVal, - RequireLinearHistory: &falseVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &trueVal, + AllowForcePushes: &falseVal, + EnforceAdmins: &trueVal, + RequireLinearHistory: &falseVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -333,11 +347,13 @@ func Test_applyRepoRules(t *testing.T) { }, expected: &clients.BranchRef{ BranchProtectionRule: clients.BranchProtectionRule{ - AllowDeletions: &trueVal, - AllowForcePushes: &trueVal, - RequireLinearHistory: &trueVal, - EnforceAdmins: &trueVal, - RequiredPullRequestReviews: nil, + AllowDeletions: &trueVal, + AllowForcePushes: &trueVal, + RequireLinearHistory: &trueVal, + EnforceAdmins: &trueVal, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -362,7 +378,8 @@ func Test_applyRepoRules(t *testing.T) { EnforceAdmins: &trueVal, RequireLastPushApproval: &trueVal, RequireLinearHistory: &falseVal, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, RequiredApprovingReviewCount: &zeroVal, }, }, @@ -392,7 +409,8 @@ func Test_applyRepoRules(t *testing.T) { EnforceAdmins: &trueVal, RequireLinearHistory: &falseVal, RequireLastPushApproval: &trueVal, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, RequiredApprovingReviewCount: &twoVal, @@ -429,7 +447,9 @@ func Test_applyRepoRules(t *testing.T) { RequiresStatusChecks: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: nil, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + }, }, }, }, @@ -495,7 +515,8 @@ func Test_applyRepoRules(t *testing.T) { RequiresStatusChecks: &trueVal, Contexts: []string{"foo"}, }, - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &trueVal, RequiredApprovingReviewCount: &twoVal, DismissStaleReviews: &trueVal, RequireCodeOwnerReviews: &trueVal, @@ -556,7 +577,10 @@ func Test_translationFromGithubAPIBranchProtectionData(t *testing.T) { RequiresStatusChecks: nil, Contexts: []string{}, }, - RequiredPullRequestReviews: nil, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + RequiredApprovingReviewCount: asPtr[int32](0), + RequireCodeOwnerReviews: &falseVal, + }, }, }, }, @@ -591,7 +615,12 @@ func Test_translationFromGithubAPIBranchProtectionData(t *testing.T) { RequiresStatusChecks: &falseVal, Contexts: []string{}, }, - RequiredPullRequestReviews: nil, + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: &falseVal, + RequireCodeOwnerReviews: &falseVal, + DismissStaleReviews: &falseVal, + RequiredApprovingReviewCount: nil, + }, }, }, }, diff --git a/clients/gitlabrepo/branches.go b/clients/gitlabrepo/branches.go index bd69d7e613e..f50f5e3cdb0 100644 --- a/clients/gitlabrepo/branches.go +++ b/clients/gitlabrepo/branches.go @@ -193,7 +193,8 @@ func makeBranchRefFrom(branch *gitlab.Branch, protectedBranch *gitlab.ProtectedB Contexts: makeContextsFromResp(projectStatusChecks), } - pullRequestReviewRule := &clients.PullRequestReviewRule{ + pullRequestReviewRule := clients.PullRequestReviewRule{ + // TODO how do we know if they're required? DismissStaleReviews: newTrue(), RequireCodeOwnerReviews: &protectedBranch.CodeOwnerApprovalRequired, } diff --git a/cron/internal/format/json_raw_results.go b/cron/internal/format/json_raw_results.go index 9c19227c31e..1a2d6e64331 100644 --- a/cron/internal/format/json_raw_results.go +++ b/cron/internal/format/json_raw_results.go @@ -210,17 +210,15 @@ func addBranchProtectionRawResults(r *jsonScorecardRawResult, bp *checker.Branch bp = &jsonBranchProtectionSettings{ AllowsDeletions: v.BranchProtectionRule.AllowDeletions, AllowsForcePushes: v.BranchProtectionRule.AllowForcePushes, + RequiresCodeOwnerReviews: v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews, RequiresLinearHistory: v.BranchProtectionRule.RequireLinearHistory, + DismissesStaleReviews: v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews, EnforcesAdmins: v.BranchProtectionRule.EnforceAdmins, RequiresStatusChecks: v.BranchProtectionRule.CheckRules.RequiresStatusChecks, RequiresUpToDateBranchBeforeMerging: v.BranchProtectionRule.CheckRules.UpToDateBeforeMerge, + RequiredApprovingReviewCount: v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, StatusCheckContexts: v.BranchProtectionRule.CheckRules.Contexts, } - if v.BranchProtectionRule.RequiredPullRequestReviews != nil { - bp.DismissesStaleReviews = v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews - bp.RequiredApprovingReviewCount = v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount - bp.RequiresCodeOwnerReviews = v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews - } } r.Results.BranchProtections = append(r.Results.BranchProtections, jsonBranchProtection{ Name: *v.Name, diff --git a/pkg/json_raw_results.go b/pkg/json_raw_results.go index 7f2ef29d135..5d63cacfec8 100644 --- a/pkg/json_raw_results.go +++ b/pkg/json_raw_results.go @@ -712,17 +712,15 @@ func (r *jsonScorecardRawResult) addBranchProtectionRawResults(bp *checker.Branc bp = &jsonBranchProtectionSettings{ AllowsDeletions: v.BranchProtectionRule.AllowDeletions, AllowsForcePushes: v.BranchProtectionRule.AllowForcePushes, + RequiresCodeOwnerReviews: v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews, RequiresLinearHistory: v.BranchProtectionRule.RequireLinearHistory, + DismissesStaleReviews: v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews, EnforcesAdmins: v.BranchProtectionRule.EnforceAdmins, RequiresStatusChecks: v.BranchProtectionRule.CheckRules.RequiresStatusChecks, RequiresUpToDateBranchBeforeMerging: v.BranchProtectionRule.CheckRules.UpToDateBeforeMerge, + RequiredApprovingReviewCount: v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount, StatusCheckContexts: v.BranchProtectionRule.CheckRules.Contexts, } - if v.BranchProtectionRule.RequiredPullRequestReviews != nil { - bp.DismissesStaleReviews = v.BranchProtectionRule.RequiredPullRequestReviews.DismissStaleReviews - bp.RequiredApprovingReviewCount = v.BranchProtectionRule.RequiredPullRequestReviews.RequiredApprovingReviewCount - bp.RequiresCodeOwnerReviews = v.BranchProtectionRule.RequiredPullRequestReviews.RequireCodeOwnerReviews - } } branches = append(branches, jsonBranchProtection{ Name: *v.Name, diff --git a/pkg/json_raw_results_test.go b/pkg/json_raw_results_test.go index 098d6dfc974..261e6f81cee 100644 --- a/pkg/json_raw_results_test.go +++ b/pkg/json_raw_results_test.go @@ -1114,7 +1114,8 @@ func TestJsonScorecardRawResult(t *testing.T) { BranchProtectionRule: clients.BranchProtectionRule{ AllowDeletions: boolPtr(true), AllowForcePushes: boolPtr(false), - RequiredPullRequestReviews: &clients.PullRequestReviewRule{ + RequiredPullRequestReviews: clients.PullRequestReviewRule{ + Required: boolPtr(true), RequireCodeOwnerReviews: boolPtr(true), DismissStaleReviews: boolPtr(true), RequiredApprovingReviewCount: intPtr(2), From 2c20be03cb807bee3b6da9553a32a75a1e61d85b Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:51:32 +0000 Subject: [PATCH 45/51] convert Signed Releases to probes (#3610) * convert Signed Releases to probes Signed-off-by: AdamKorcz * Specify that probe is for Github and Gitlab only Signed-off-by: AdamKorcz * use in loop instead of Signed-off-by: AdamKorcz * fix linter issues Signed-off-by: AdamKorcz * fix more linter issues Signed-off-by: AdamKorcz * specify Github and Gitlab in provenance def.yml Signed-off-by: AdamKorcz * Add link to slsa-github-generator Signed-off-by: AdamKorcz * Add instructions on signing with Cosign Signed-off-by: AdamKorcz * refactor evaluation Signed-off-by: Adam Korczynski * debug failing integration test Signed-off-by: Adam Korczynski * remove unused nolints Signed-off-by: Adam Korczynski * expose release name asset names in finding values Signed-off-by: Adam Korczynski * fix failed integration test Signed-off-by: Adam Korczynski * remove 'totalReleases' value from findings Signed-off-by: Adam Korczynski * remove left-over cases of "totalReleases" values in findings Signed-off-by: Adam Korczynski * remove remaining totalReleases values Signed-off-by: Adam Korczynski * use const probe names instead of hard-coded strings Signed-off-by: Adam Korczynski * remove totalReleases from test helper arguments Signed-off-by: Adam Korczynski * merge test helpers Signed-off-by: Adam Korczynski --------- Signed-off-by: AdamKorcz Signed-off-by: Adam Korczynski --- checks/evaluation/signed_releases.go | 191 +++++++------ checks/evaluation/signed_releases_test.go | 299 ++++++++++++++++----- checks/signed_releases.go | 16 +- checks/signed_releases_test.go | 79 ++++++ probes/entries.go | 7 + probes/releasesAreSigned/def.yml | 30 +++ probes/releasesAreSigned/impl.go | 133 +++++++++ probes/releasesAreSigned/impl_test.go | 261 ++++++++++++++++++ probes/releasesHaveProvenance/def.yml | 28 ++ probes/releasesHaveProvenance/impl.go | 134 +++++++++ probes/releasesHaveProvenance/impl_test.go | 183 +++++++++++++ 11 files changed, 1208 insertions(+), 153 deletions(-) create mode 100644 probes/releasesAreSigned/def.yml create mode 100644 probes/releasesAreSigned/impl.go create mode 100644 probes/releasesAreSigned/impl_test.go create mode 100644 probes/releasesHaveProvenance/def.yml create mode 100644 probes/releasesHaveProvenance/impl.go create mode 100644 probes/releasesHaveProvenance/impl_test.go diff --git a/checks/evaluation/signed_releases.go b/checks/evaluation/signed_releases.go index 5feb11b680f..9f3673ffe21 100644 --- a/checks/evaluation/signed_releases.go +++ b/checks/evaluation/signed_releases.go @@ -17,118 +17,137 @@ package evaluation import ( "fmt" "math" - "strings" "github.com/ossf/scorecard/v4/checker" sce "github.com/ossf/scorecard/v4/errors" "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/releasesAreSigned" + "github.com/ossf/scorecard/v4/probes/releasesHaveProvenance" ) -var ( - signatureExtensions = []string{".asc", ".minisig", ".sig", ".sign"} - provenanceExtensions = []string{".intoto.jsonl"} -) - -const releaseLookBack = 5 - // SignedReleases applies the score policy for the Signed-Releases check. -// -//nolint:gocognit -func SignedReleases(name string, dl checker.DetailLogger, r *checker.SignedReleasesData) checker.CheckResult { - if r == nil { - e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") +func SignedReleases(name string, + findings []finding.Finding, dl checker.DetailLogger, +) checker.CheckResult { + expectedProbes := []string{ + releasesAreSigned.Probe, + releasesHaveProvenance.Probe, + } + + if !finding.UniqueProbesEqual(findings, expectedProbes) { + e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results") return checker.CreateRuntimeErrorResult(name, e) } - totalReleases := 0 - total := 0 - score := 0 - for _, release := range r.Releases { - if len(release.Assets) == 0 { - continue + // Debug all releases and check for OutcomeNotApplicable + // All probes have OutcomeNotApplicable in case the project has no + // releases. Therefore, check for any finding with OutcomeNotApplicable. + loggedReleases := make([]string, 0) + for i := range findings { + f := &findings[i] + + // Debug release name + releaseName, err := getReleaseName(f) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, "could not get release name") + return checker.CreateRuntimeErrorResult(name, e) + } + if !contains(loggedReleases, releaseName) { + dl.Debug(&checker.LogMessage{ + Text: fmt.Sprintf("GitHub release found: %s", releaseName), + }) + loggedReleases = append(loggedReleases, releaseName) } - dl.Debug(&checker.LogMessage{ - Text: fmt.Sprintf("GitHub release found: %s", release.TagName), - }) - - totalReleases++ - signed := false - hasProvenance := false - - // Check for provenance. - for _, asset := range release.Assets { - for _, suffix := range provenanceExtensions { - if strings.HasSuffix(asset.Name, suffix) { - dl.Info(&checker.LogMessage{ - Path: asset.URL, - Type: finding.FileTypeURL, - Text: fmt.Sprintf("provenance for release artifact: %s", asset.Name), - }) - hasProvenance = true - total++ - break - } - } - if hasProvenance { - // Assign maximum points. - score += 10 - break - } + // Check if outcome is NotApplicable + if f.Outcome == finding.OutcomeNotApplicable { + dl.Warn(&checker.LogMessage{ + Text: "no GitHub releases found", + }) + // Generic summary. + return checker.CreateInconclusiveResult(name, "no releases found") + } + } + + totalPositive := 0 + releaseMap := make(map[string]int) + uniqueReleaseTags := make([]string, 0) + checker.LogFindings(findings, dl) + + for i := range findings { + f := &findings[i] + + releaseName, err := getReleaseName(f) + if err != nil { + return checker.CreateRuntimeErrorResult(name, err) } - if hasProvenance { - continue + if !contains(uniqueReleaseTags, releaseName) { + uniqueReleaseTags = append(uniqueReleaseTags, releaseName) } - dl.Warn(&checker.LogMessage{ - Path: release.URL, - Type: finding.FileTypeURL, - Text: fmt.Sprintf("release artifact %s does not have provenance", release.TagName), - }) - - // No provenance. Try signatures. - for _, asset := range release.Assets { - for _, suffix := range signatureExtensions { - if strings.HasSuffix(asset.Name, suffix) { - dl.Info(&checker.LogMessage{ - Path: asset.URL, - Type: finding.FileTypeURL, - Text: fmt.Sprintf("signed release artifact: %s", asset.Name), - }) - signed = true - total++ - break + if f.Outcome == finding.OutcomePositive { + totalPositive++ + + switch f.Probe { + case releasesAreSigned.Probe: + if _, ok := releaseMap[releaseName]; !ok { + releaseMap[releaseName] = 8 } - } - if signed { - // Assign 8 points. - score += 8 - break + case releasesHaveProvenance.Probe: + releaseMap[releaseName] = 10 } } + } - if !signed { - dl.Warn(&checker.LogMessage{ - Path: release.URL, - Type: finding.FileTypeURL, - Text: fmt.Sprintf("release artifact %s not signed", release.TagName), - }) - } - if totalReleases >= releaseLookBack { - break - } + if totalPositive == 0 { + return checker.CreateMinScoreResult(name, "Project has not signed or included provenance with any releases.") } + totalReleases := len(uniqueReleaseTags) + + if totalReleases > 5 { + totalReleases = 5 + } if totalReleases == 0 { - dl.Warn(&checker.LogMessage{ - Text: "no GitHub releases found", - }) - // Generic summary. + // This should not happen in production, but it is useful to have + // for testing. return checker.CreateInconclusiveResult(name, "no releases found") } + score := 0 + for _, s := range releaseMap { + score += s + } + score = int(math.Floor(float64(score) / float64(totalReleases))) - reason := fmt.Sprintf("%d out of %d artifacts are signed or have provenance", total, totalReleases) + reason := fmt.Sprintf("%d out of the last %d releases have a total of %d signed artifacts.", + len(releaseMap), totalReleases, totalPositive) return checker.CreateResultWithScore(name, reason, score) } + +func getReleaseName(f *finding.Finding) (string, error) { + m := f.Values + for k, v := range m { + var value int + switch f.Probe { + case releasesAreSigned.Probe: + value = int(releasesAreSigned.ValueTypeRelease) + case releasesHaveProvenance.Probe: + value = int(releasesHaveProvenance.ValueTypeRelease) + } + if v == value { + return k, nil + } + } + return "", sce.WithMessage(sce.ErrScorecardInternal, "could not get release tag") +} + +func contains(releases []string, release string) bool { + for _, r := range releases { + if r == release { + return true + } + } + return false +} diff --git a/checks/evaluation/signed_releases_test.go b/checks/evaluation/signed_releases_test.go index 53a8ee362e2..8aa8c8fe5f4 100644 --- a/checks/evaluation/signed_releases_test.go +++ b/checks/evaluation/signed_releases_test.go @@ -15,96 +15,269 @@ package evaluation import ( + "fmt" "testing" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/releasesAreSigned" + "github.com/ossf/scorecard/v4/probes/releasesHaveProvenance" scut "github.com/ossf/scorecard/v4/utests" ) +const ( + release0 = 0 + release1 = 1 + release2 = 2 + release3 = 3 + release4 = 4 +) + +const ( + asset0 = 0 + asset1 = 1 + asset2 = 2 + asset3 = 3 + asset4 = 4 + asset5 = 5 + asset6 = 6 + asset7 = 7 + asset8 = 8 + asset9 = 9 +) + +func signedProbe(release, asset int, outcome finding.Outcome) finding.Finding { + return finding.Finding{ + Probe: releasesAreSigned.Probe, + Outcome: outcome, + Values: map[string]int{ + fmt.Sprintf("v%d", release): int(releasesAreSigned.ValueTypeRelease), + fmt.Sprintf("artifact-%d", asset): int(releasesAreSigned.ValueTypeReleaseAsset), + }, + } +} + +func provenanceProbe(release, asset int, outcome finding.Outcome) finding.Finding { + return finding.Finding{ + Probe: releasesHaveProvenance.Probe, + Outcome: outcome, + Values: map[string]int{ + fmt.Sprintf("v%d", release): int(releasesHaveProvenance.ValueTypeRelease), + fmt.Sprintf("artifact-%d", asset): int(releasesHaveProvenance.ValueTypeReleaseAsset), + }, + } +} + func TestSignedReleases(t *testing.T) { t.Parallel() tests := []struct { - name string - releases []clients.Release - expectedResult checker.CheckResult + name string + findings []finding.Finding + result scut.TestReturn }{ { - name: "Full score", - releases: []clients.Release{ - { - TagName: "v1.0", - Assets: []clients.ReleaseAsset{ - {Name: "binary.tar.gz"}, - {Name: "binary.tar.gz.sig"}, - {Name: "binary.tar.gz.intoto.jsonl"}, - }, - }, + name: "Has one release that is signed but no provenance", + findings: []finding.Finding{ + signedProbe(0, 0, finding.OutcomePositive), + provenanceProbe(0, 0, finding.OutcomeNegative), }, - expectedResult: checker.CheckResult{ - Name: "Signed-Releases", - Version: 2, - Score: 10, - Reason: "1 out of 1 artifacts are signed or have provenance", + result: scut.TestReturn{ + Score: 8, + NumberOfInfo: 1, + NumberOfWarn: 1, + NumberOfDebug: 1, }, }, { - name: "Partial score", - releases: []clients.Release{ - { - TagName: "v1.0", - Assets: []clients.ReleaseAsset{ - {Name: "binary.tar.gz"}, - {Name: "binary.tar.gz.sig"}, - }, - }, + name: "Has one release that is signed and has provenance", + findings: []finding.Finding{ + signedProbe(0, 0, finding.OutcomePositive), + provenanceProbe(0, 0, finding.OutcomePositive), }, - expectedResult: checker.CheckResult{ - Name: "Signed-Releases", - Version: 2, - Score: 8, - Reason: "1 out of 1 artifacts are signed or have provenance", + result: scut.TestReturn{ + Score: 10, + NumberOfInfo: 2, + NumberOfDebug: 1, }, }, { - name: "No score", - releases: []clients.Release{ - { - TagName: "v1.0", - Assets: []clients.ReleaseAsset{ - {Name: "binary.tar.gz"}, - }, - }, + name: "Has one release that is not signed but has provenance", + findings: []finding.Finding{ + signedProbe(0, 0, finding.OutcomeNegative), + provenanceProbe(0, 0, finding.OutcomePositive), }, - expectedResult: checker.CheckResult{ - Name: "Signed-Releases", - Version: 2, - Score: 0, - Reason: "0 out of 1 artifacts are signed or have provenance", + result: scut.TestReturn{ + Score: checker.MaxResultScore, + NumberOfInfo: 1, + NumberOfWarn: 1, + NumberOfDebug: 1, + }, + }, + + { + name: "3 releases. One release has one signed, and one release has two provenance.", + findings: []finding.Finding{ + // Release 1: + // Asset 1: + signedProbe(release0, asset0, finding.OutcomeNegative), + provenanceProbe(release0, asset0, finding.OutcomeNegative), + // Asset 2: + signedProbe(release0, asset1, finding.OutcomePositive), + provenanceProbe(release0, asset1, finding.OutcomeNegative), + // Release 2 + // Asset 1: + signedProbe(release1, asset0, finding.OutcomeNegative), + provenanceProbe(release1, asset0, finding.OutcomeNegative), + // Release 2 + // Asset 2: + signedProbe(release1, asset1, finding.OutcomeNegative), + provenanceProbe(release1, asset1, finding.OutcomeNegative), + // Release 2 + // Asset 3: + signedProbe(release1, asset2, finding.OutcomeNegative), + provenanceProbe(release1, asset2, finding.OutcomeNegative), + // Release 3 + // Asset 1: + signedProbe(release2, asset0, finding.OutcomeNegative), + provenanceProbe(release2, asset0, finding.OutcomePositive), + // Asset 2: + signedProbe(release2, asset1, finding.OutcomeNegative), + provenanceProbe(release2, asset1, finding.OutcomePositive), + // Asset 3: + signedProbe(release2, asset2, finding.OutcomeNegative), + provenanceProbe(release2, asset2, finding.OutcomeNegative), + }, + result: scut.TestReturn{ + Score: 6, + NumberOfInfo: 3, + NumberOfWarn: 13, + NumberOfDebug: 3, + }, + }, + { + name: "5 releases. Two releases have one signed each, and two releases have one provenance each.", + findings: []finding.Finding{ + // Release 1: + // Release 1, Asset 1: + signedProbe(release0, asset0, finding.OutcomeNegative), + provenanceProbe(release0, asset0, finding.OutcomeNegative), + signedProbe(release0, asset1, finding.OutcomePositive), + provenanceProbe(release0, asset1, finding.OutcomeNegative), + // Release 2: + // Release 2, Asset 1: + signedProbe(release1, asset1, finding.OutcomePositive), + provenanceProbe(release1, asset0, finding.OutcomeNegative), + // Release 2, Asset 2: + signedProbe(release1, asset1, finding.OutcomeNegative), + provenanceProbe(release1, asset1, finding.OutcomeNegative), + // Release 2, Asset 3: + signedProbe(release1, asset2, finding.OutcomeNegative), + provenanceProbe(release1, asset2, finding.OutcomeNegative), + // Release 3, Asset 1: + signedProbe(release2, asset0, finding.OutcomeNegative), + provenanceProbe(release2, asset0, finding.OutcomePositive), + // Release 3, Asset 2: + signedProbe(release2, asset1, finding.OutcomeNegative), + provenanceProbe(release2, asset1, finding.OutcomeNegative), + // Release 3, Asset 3: + signedProbe(release2, asset2, finding.OutcomeNegative), + provenanceProbe(release2, asset2, finding.OutcomeNegative), + // Release 4, Asset 1: + signedProbe(release3, asset0, finding.OutcomeNegative), + provenanceProbe(release3, asset0, finding.OutcomePositive), + // Release 4, Asset 2: + signedProbe(release3, asset1, finding.OutcomeNegative), + provenanceProbe(release3, asset1, finding.OutcomeNegative), + // Release 4, Asset 3: + signedProbe(release3, asset2, finding.OutcomeNegative), + provenanceProbe(release3, asset2, finding.OutcomeNegative), + // Release 5, Asset 1: + signedProbe(release4, asset0, finding.OutcomeNegative), + provenanceProbe(release4, asset0, finding.OutcomeNegative), + // Release 5, Asset 2: + signedProbe(release4, asset1, finding.OutcomeNegative), + provenanceProbe(release4, asset1, finding.OutcomeNegative), + // Release 5, Asset 3: + signedProbe(release4, asset2, finding.OutcomeNegative), + provenanceProbe(release4, asset2, finding.OutcomeNegative), + // Release 5, Asset 4: + signedProbe(release4, asset3, finding.OutcomeNegative), + provenanceProbe(release4, asset3, finding.OutcomeNegative), + }, + result: scut.TestReturn{ + Score: 7, + NumberOfInfo: 4, + NumberOfWarn: 26, + NumberOfDebug: 5, }, }, { - name: "No releases", - releases: []clients.Release{}, - expectedResult: checker.CreateInconclusiveResult("Signed-Releases", "no releases found"), + name: "5 releases. All have one signed artifact.", + findings: []finding.Finding{ + // Release 1: + // Release 1, Asset 1: + signedProbe(release0, asset0, finding.OutcomeNegative), + provenanceProbe(release0, asset0, finding.OutcomeNegative), + signedProbe(release0, asset1, finding.OutcomePositive), + provenanceProbe(release0, asset1, finding.OutcomeNegative), + // Release 2: + // Release 2, Asset 1: + signedProbe(release1, asset0, finding.OutcomePositive), + provenanceProbe(release1, asset0, finding.OutcomeNegative), + // Release 2, Asset 2: + signedProbe(release1, asset1, finding.OutcomeNegative), + provenanceProbe(release1, asset1, finding.OutcomeNegative), + // Release 2, Asset 3: + signedProbe(release1, asset2, finding.OutcomeNegative), + provenanceProbe(release1, asset2, finding.OutcomeNegative), + // Release 3, Asset 1: + signedProbe(release2, asset0, finding.OutcomePositive), + provenanceProbe(release2, asset0, finding.OutcomePositive), + // Release 3, Asset 2: + signedProbe(release2, asset1, finding.OutcomeNegative), + provenanceProbe(release2, asset1, finding.OutcomeNegative), + // Release 3, Asset 3: + signedProbe(release2, asset2, finding.OutcomeNegative), + provenanceProbe(release2, asset2, finding.OutcomeNegative), + // Release 4, Asset 1: + signedProbe(release3, asset0, finding.OutcomePositive), + provenanceProbe(release3, asset0, finding.OutcomePositive), + // Release 4, Asset 2: + signedProbe(release3, asset1, finding.OutcomeNegative), + provenanceProbe(release3, asset1, finding.OutcomeNegative), + // Release 4, Asset 3: + signedProbe(release3, asset2, finding.OutcomeNegative), + provenanceProbe(release3, asset2, finding.OutcomeNegative), + // Release 5, Asset 1: + signedProbe(release4, asset0, finding.OutcomePositive), + provenanceProbe(release4, asset0, finding.OutcomeNegative), + // Release 5, Asset 2: + signedProbe(release4, asset1, finding.OutcomeNegative), + provenanceProbe(release4, asset1, finding.OutcomeNegative), + // Release 5, Asset 3: + signedProbe(release4, asset2, finding.OutcomeNegative), + provenanceProbe(release4, asset2, finding.OutcomeNegative), + // Release 5, Asset 4: + signedProbe(release4, asset3, finding.OutcomeNegative), + provenanceProbe(release4, asset3, finding.OutcomeNegative), + }, + result: scut.TestReturn{ + Score: 8, + NumberOfInfo: 7, + NumberOfWarn: 23, + NumberOfDebug: 5, + }, }, } - for _, tc := range tests { - tc := tc - t.Run(tc.name, func(t *testing.T) { + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { t.Parallel() - dl := &scut.TestDetailLogger{} - data := &checker.SignedReleasesData{Releases: tc.releases} - actualResult := SignedReleases("Signed-Releases", dl, data) - - if !cmp.Equal(tc.expectedResult, actualResult, - cmpopts.IgnoreFields(checker.CheckResult{}, "Error")) { - t.Errorf("SignedReleases() mismatch (-want +got):\n%s", cmp.Diff(tc.expectedResult, actualResult, - cmpopts.IgnoreFields(checker.CheckResult{}, "Error"))) + dl := scut.TestDetailLogger{} + got := SignedReleases(tt.name, tt.findings, &dl) + if !scut.ValidateTestReturn(t, tt.name, &tt.result, &got, &dl) { + t.Errorf("got %v, expected %v", got, tt.result) } }) } diff --git a/checks/signed_releases.go b/checks/signed_releases.go index be2dfe98a61..522672431f7 100644 --- a/checks/signed_releases.go +++ b/checks/signed_releases.go @@ -19,6 +19,8 @@ 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" + "github.com/ossf/scorecard/v4/probes/zrunner" ) // CheckSignedReleases is the registered name for SignedReleases. @@ -40,11 +42,17 @@ func SignedReleases(c *checker.CheckRequest) checker.CheckResult { return checker.CreateRuntimeErrorResult(CheckSignedReleases, e) } - // Return raw results. - if c.RawResults != nil { - c.RawResults.SignedReleasesResults = rawData + // Set the raw results. + pRawResults := getRawResults(c) + pRawResults.SignedReleasesResults = rawData + + // Evaluate the probes. + findings, err := zrunner.Run(pRawResults, probes.SignedReleases) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckFuzzing, e) } // Return the score evaluation. - return evaluation.SignedReleases(CheckSignedReleases, c.Dlogger, &rawData) + return evaluation.SignedReleases(CheckSignedReleases, findings, c.Dlogger) } diff --git a/checks/signed_releases_test.go b/checks/signed_releases_test.go index 39bdc017fb7..b12268f3155 100644 --- a/checks/signed_releases_test.go +++ b/checks/signed_releases_test.go @@ -16,6 +16,7 @@ package checks import ( "errors" + "fmt" "testing" "github.com/golang/mock/gomock" @@ -362,6 +363,42 @@ func TestSignedRelease(t *testing.T) { }, }, + { + name: "Error getting releases", + err: errors.New("Error getting releases"), + expected: checker.CheckResult{ + Score: -1, + Error: errors.New("Error getting releases"), + }, + }, + { + name: "9 Releases with assests with signed artifacts", + releases: []clients.Release{ + release("v0.8.5"), + release("v0.8.4"), + release("v0.8.3"), + release("v0.8.2"), + release("v0.8.1"), + release("v0.8.0"), + release("v0.7.0"), + release("v0.6.0"), + release("v0.5.0"), + release("v0.4.0"), + release("v0.3.0"), + release("v0.2.0"), + release("v0.1.0"), + release("v0.0.6"), + release("v0.0.5"), + release("v0.0.4"), + release("v0.0.3"), + release("v0.0.2"), + release("v0.0.1"), + }, + expected: checker.CheckResult{ + Score: 8, + }, + }, + { name: "Error getting releases", err: errors.New("Error getting releases"), @@ -410,3 +447,45 @@ func TestSignedRelease(t *testing.T) { }) } } + +func release(version string) clients.Release { + return clients.Release{ + TagName: version, + URL: fmt.Sprintf("https://github.com/test/test_artifact/releases/tag/%s", version), + TargetCommitish: "master", + Assets: []clients.ReleaseAsset{ + { + Name: fmt.Sprintf("%s_checksums.txt", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_checksums.txt", version, version), + }, + { + Name: fmt.Sprintf("%s_checksums.txt.sig", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_checksums.txt.sig", version, version), + }, + { + Name: fmt.Sprintf("%s_darwin_x86_64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_darwin_x86_64.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_Linux_arm64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_Linux_arm64.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_Linux_i386.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_Linux_i386.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_Linux_x86_64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_Linux_x86_64.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_windows_i386.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_windows_i386.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_windows_x86_64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_windows_x86_64.tar.gz", version, version), + }, + }, + } +} diff --git a/probes/entries.go b/probes/entries.go index 6414d224e21..3ae6dcae2ad 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -45,6 +45,8 @@ import ( "github.com/ossf/scorecard/v4/probes/notArchived" "github.com/ossf/scorecard/v4/probes/notCreatedRecently" "github.com/ossf/scorecard/v4/probes/packagedWithAutomatedWorkflow" + "github.com/ossf/scorecard/v4/probes/releasesAreSigned" + "github.com/ossf/scorecard/v4/probes/releasesHaveProvenance" "github.com/ossf/scorecard/v4/probes/sastToolCodeQLInstalled" "github.com/ossf/scorecard/v4/probes/sastToolRunsOnAllCommits" "github.com/ossf/scorecard/v4/probes/sastToolSonarInstalled" @@ -117,6 +119,7 @@ var ( hasDangerousWorkflowScriptInjection.Run, hasDangerousWorkflowUntrustedCheckout.Run, } + Maintained = []ProbeImpl{ notArchived.Run, hasRecentCommits.Run, @@ -135,6 +138,10 @@ var ( CITests = []ProbeImpl{ testsRunInCI.Run, } + SignedReleases = []ProbeImpl{ + releasesAreSigned.Run, + releasesHaveProvenance.Run, + } probeRunners = map[string]func(*checker.RawResults) ([]finding.Finding, string, error){ securityPolicyPresent.Probe: securityPolicyPresent.Run, diff --git a/probes/releasesAreSigned/def.yml b/probes/releasesAreSigned/def.yml new file mode 100644 index 00000000000..5c77599a067 --- /dev/null +++ b/probes/releasesAreSigned/def.yml @@ -0,0 +1,30 @@ +# 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: releasesAreSigned +short: Check that the projects Github and Gitlab releases are signed. +motivation: > + Signed releases allow consumers to verify their artifacts before consuming them. +implementation: > + The implementation checks whether a signature file is present in release assets. The probe checks the last 5 releases on Github and Gitlab. +outcome: + - For each of the last 5 releases, the probe returns OutcomePositive, if the release has a signature file in the release assets. + - For each of the last 5 releases, the probe returns OutcomeNegative, if the the release does not have a signature file in the release assets. + - If the project has no releases, the probe returns OutcomeNotApplicable. +remediation: + effort: Medium + text: + - Install Cosign by following https://docs.sigstore.dev/system_config/installation + - Sign your release artifacts using `cosign sign $YOUR_ARTIFACT`. See more at https://docs.sigstore.dev/signing/quickstart + - Publish your release and add the certificate and signature produced by Cosign. diff --git a/probes/releasesAreSigned/impl.go b/probes/releasesAreSigned/impl.go new file mode 100644 index 00000000000..735cc141df3 --- /dev/null +++ b/probes/releasesAreSigned/impl.go @@ -0,0 +1,133 @@ +// 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. + +//nolint:stylecheck +package releasesAreSigned + +import ( + "embed" + "fmt" + "strings" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + Probe = "releasesAreSigned" + releaseLookBack = 5 +) + +// ValueType is the type of a value in the finding values. +type ValueType int + +const ( + // ValueTypeRelease represents a release name. + ValueTypeRelease ValueType = iota + // ValueTypeReleaseAsset represents a release asset name. + ValueTypeReleaseAsset +) + +var signatureExtensions = []string{".asc", ".minisig", ".sig", ".sign"} + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + var findings []finding.Finding + + releases := raw.SignedReleasesResults.Releases + + totalReleases := 0 + for releaseIndex, release := range releases { + if len(release.Assets) == 0 { + continue + } + + if releaseIndex == releaseLookBack { + break + } + + totalReleases++ + signed := false + for j := range release.Assets { + asset := release.Assets[j] + for _, suffix := range signatureExtensions { + if !strings.HasSuffix(asset.Name, suffix) { + continue + } + // Create Positive Finding + // with file info + loc := &finding.Location{ + Type: finding.FileTypeURL, + Path: asset.URL, + } + f, err := finding.NewWith(fs, Probe, + fmt.Sprintf("signed release artifact: %s", asset.Name), + loc, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f.Values = map[string]int{ + release.TagName: int(ValueTypeRelease), + asset.Name: int(ValueTypeReleaseAsset), + } + findings = append(findings, *f) + signed = true + break + } + if signed { + break + } + } + if signed { + continue + } + + // Release is not signed + loc := &finding.Location{ + Type: finding.FileTypeURL, + Path: release.URL, + } + f, err := finding.NewWith(fs, Probe, + fmt.Sprintf("release artifact %s not signed", release.TagName), + loc, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f.Values = map[string]int{ + release.TagName: int(ValueTypeRelease), + } + findings = append(findings, *f) + } + + if len(findings) == 0 { + f, err := finding.NewWith(fs, Probe, + "no GitHub/GitLab releases found", + nil, + finding.OutcomeNotApplicable) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + return findings, Probe, nil +} diff --git a/probes/releasesAreSigned/impl_test.go b/probes/releasesAreSigned/impl_test.go new file mode 100644 index 00000000000..71b8e4444a0 --- /dev/null +++ b/probes/releasesAreSigned/impl_test.go @@ -0,0 +1,261 @@ +// 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. + +//nolint:stylecheck +package releasesAreSigned + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "Has one signed release.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Has two signed releases.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + { + TagName: "v2.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + finding.OutcomePositive, + }, + }, + { + name: "Has two unsigned releases.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.notSig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + { + TagName: "v2.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.notSig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomeNegative, + }, + }, + { + name: "Has two unsigned releases and one signed release.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.notSig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + { + TagName: "v2.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + + { + TagName: "v3.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.notSig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomePositive, + finding.OutcomeNegative, + }, + }, + { + name: "Many releases.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + release("v0.8.5"), + release("v0.8.4"), + release("v0.8.3"), + release("v0.8.2"), + release("v0.8.1"), + release("v0.8.0"), + release("v0.7.0"), + release("v0.6.0"), + release("v0.5.0"), + release("v0.4.0"), + release("v0.3.0"), + release("v0.2.0"), + release("v0.1.0"), + release("v0.0.6"), + release("v0.0.5"), + release("v0.0.4"), + release("v0.0.3"), + release("v0.0.2"), + release("v0.0.1"), + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + finding.OutcomePositive, + finding.OutcomePositive, + finding.OutcomePositive, + finding.OutcomePositive, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} + +func release(version string) clients.Release { + return clients.Release{ + TagName: version, + URL: fmt.Sprintf("https://github.com/test/test_artifact/releases/tag/%s", version), + TargetCommitish: "master", + Assets: []clients.ReleaseAsset{ + { + Name: fmt.Sprintf("%s_checksums.txt", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_checksums.txt", version, version), + }, + { + Name: fmt.Sprintf("%s_checksums.txt.sig", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_checksums.txt.sig", version, version), + }, + { + Name: fmt.Sprintf("%s_darwin_x86_64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_darwin_x86_64.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_Linux_arm64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_Linux_arm64.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_Linux_i386.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_Linux_i386.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_Linux_x86_64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_Linux_x86_64.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_windows_i386.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_windows_i386.tar.gz", version, version), + }, + { + Name: fmt.Sprintf("%s_windows_x86_64.tar.gz", version), + URL: fmt.Sprintf("https://github.com/test/repo/releases/%s/%s_windows_x86_64.tar.gz", version, version), + }, + }, + } +} diff --git a/probes/releasesHaveProvenance/def.yml b/probes/releasesHaveProvenance/def.yml new file mode 100644 index 00000000000..4cb0dc70b74 --- /dev/null +++ b/probes/releasesHaveProvenance/def.yml @@ -0,0 +1,28 @@ +# 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: releasesHaveProvenance +short: Check that the projects releases on Github and Gitlab have provenance. +motivation: > + Provenance give users security-critical, verifiable information so that consumers can verify their artifacts before consuming them. +implementation: > + The probe checks whether any of the assets in any of the last five releases on Github or Gitlab have a provenance file. +outcome: + - For each of the last 5 releases, the probe returns OutcomePositive, if the release has a provenance file in the release assets. + - For each of the last 5 releases, the probe returns OutcomeNegative, if the the release does not have a provenance file in the release assets. + - If the project has no releases, the probe returns OutcomeNotApplicable. +remediation: + effort: Medium + text: + - Generate provenance and add it alongside the release assets. Use the [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) to add SLSA level 3 provenance to releases. diff --git a/probes/releasesHaveProvenance/impl.go b/probes/releasesHaveProvenance/impl.go new file mode 100644 index 00000000000..02ba874e091 --- /dev/null +++ b/probes/releasesHaveProvenance/impl.go @@ -0,0 +1,134 @@ +// 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. + +//nolint:stylecheck +package releasesHaveProvenance + +import ( + "embed" + "fmt" + "strings" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/finding" + "github.com/ossf/scorecard/v4/probes/internal/utils/uerror" +) + +//go:embed *.yml +var fs embed.FS + +const ( + Probe = "releasesHaveProvenance" + releaseLookBack = 5 +) + +// ValueType is the type of a value in the finding values. +type ValueType int + +const ( + // ValueTypeRelease represents a release name. + ValueTypeRelease ValueType = iota + // ValueTypeReleaseAsset represents a release asset name. + ValueTypeReleaseAsset +) + +var provenanceExtensions = []string{".intoto.jsonl"} + +func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { + if raw == nil { + return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) + } + + var findings []finding.Finding + + releases := raw.SignedReleasesResults.Releases + + totalReleases := 0 + + for i := range releases { + release := releases[i] + if len(release.Assets) == 0 { + continue + } + totalReleases++ + hasProvenance := false + for j := range release.Assets { + asset := release.Assets[j] + for _, suffix := range provenanceExtensions { + if !strings.HasSuffix(asset.Name, suffix) { + continue + } + // Create Positive Finding + // with file info + loc := &finding.Location{ + Type: finding.FileTypeURL, + Path: asset.URL, + } + f, err := finding.NewWith(fs, Probe, + fmt.Sprintf("provenance for release artifact: %s", asset.Name), + loc, + finding.OutcomePositive) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f.Values = map[string]int{ + release.TagName: int(ValueTypeRelease), + asset.Name: int(ValueTypeReleaseAsset), + } + findings = append(findings, *f) + hasProvenance = true + break + } + if hasProvenance { + break + } + } + if hasProvenance { + continue + } + + // Release does not have provenance + loc := &finding.Location{ + Type: finding.FileTypeURL, + Path: release.URL, + } + f, err := finding.NewWith(fs, Probe, + fmt.Sprintf("release artifact %s does not have provenance", release.TagName), + loc, + finding.OutcomeNegative) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + f.Values = map[string]int{ + release.TagName: int(ValueTypeRelease), + } + findings = append(findings, *f) + + if totalReleases >= releaseLookBack { + break + } + } + + if len(findings) == 0 { + f, err := finding.NewWith(fs, Probe, + "no GitHub releases found", + nil, + finding.OutcomeNotApplicable) + if err != nil { + return nil, Probe, fmt.Errorf("create finding: %w", err) + } + findings = append(findings, *f) + } + return findings, Probe, nil +} diff --git a/probes/releasesHaveProvenance/impl_test.go b/probes/releasesHaveProvenance/impl_test.go new file mode 100644 index 00000000000..bc8e148c590 --- /dev/null +++ b/probes/releasesHaveProvenance/impl_test.go @@ -0,0 +1,183 @@ +// 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. + +//nolint:stylecheck +package releasesHaveProvenance + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/finding" +) + +func Test_Run(t *testing.T) { + t.Parallel() + //nolint:govet + tests := []struct { + name string + raw *checker.RawResults + outcomes []finding.Outcome + err error + }{ + { + name: "Has one release with provenance.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + }, + }, + { + name: "Has two releases with provenance.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + { + TagName: "v2.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomePositive, + finding.OutcomePositive, + }, + }, + { + name: "Has two releases without provenance.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.notJsonl"}, + }, + }, + { + TagName: "v2.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.notJsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomeNegative, + }, + }, + { + name: "Has two releases without provenace and one with.", + raw: &checker.RawResults{ + SignedReleasesResults: checker.SignedReleasesData{ + Releases: []clients.Release{ + { + TagName: "v1.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.notSig"}, + {Name: "binary.tar.gz.intoto.notJsonl"}, + }, + }, + { + TagName: "v2.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.jsonl"}, + }, + }, + + { + TagName: "v3.0", + Assets: []clients.ReleaseAsset{ + {Name: "binary.tar.gz"}, + {Name: "binary.tar.gz.sig"}, + {Name: "binary.tar.gz.intoto.notJsonl"}, + }, + }, + }, + }, + }, + outcomes: []finding.Outcome{ + finding.OutcomeNegative, + finding.OutcomePositive, + finding.OutcomeNegative, + }, + }, + } + for _, tt := range tests { + tt := tt // Re-initializing variable so it is not changed while executing the closure below + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + findings, s, err := Run(tt.raw) + if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { + t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) + } + if err != nil { + return + } + if diff := cmp.Diff(Probe, s); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(len(tt.outcomes), len(findings)); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + for i := range tt.outcomes { + outcome := &tt.outcomes[i] + f := &findings[i] + if diff := cmp.Diff(*outcome, f.Outcome); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + } + }) + } +} From 39d1b33a195fcfaaddde03e2f613387bb9c0e177 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 21:35:02 +0000 Subject: [PATCH 46/51] :seedling: Bump the github-actions group with 2 updates (#3725) Bumps the github-actions group with 2 updates: [tj-actions/changed-files](https://github.com/tj-actions/changed-files) and [actions/stale](https://github.com/actions/stale). Updates `tj-actions/changed-files` from 40.2.1 to 40.2.2 - [Release notes](https://github.com/tj-actions/changed-files/releases) - [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md) - [Commits](https://github.com/tj-actions/changed-files/compare/1c938490c880156b746568a518594309cfb3f66b...94549999469dbfa032becf298d95c87a14c34394) Updates `actions/stale` from 8.0.0 to 9.0.0 - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/1160a2240286f5da8ec72b1c0816ce2481aabf84...28ca1036281a5e5922ead5184a1bbf96e5fc984e) --- updated-dependencies: - dependency-name: tj-actions/changed-files dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- .github/workflows/stale.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8940d178bae..ddd01d99aab 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -40,7 +40,7 @@ jobs: fetch-depth: 2 # needed to diff changed files - id: files name: Get changed files - uses: tj-actions/changed-files@1c938490c880156b746568a518594309cfb3f66b #v40.2.1 + uses: tj-actions/changed-files@94549999469dbfa032becf298d95c87a14c34394 #v40.2.2 with: files_ignore: '**.md' - id: docs_only_check diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 7d81d39ed12..b74a81041d7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -31,7 +31,7 @@ jobs: with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v3.0.18 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v3.0.18 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is stale because it has been open for 60 days with no activity.' From eefb6bfe4e50ca6902f3a5c3d7bf38afa6b4c674 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Wed, 13 Dec 2023 13:47:16 -0800 Subject: [PATCH 47/51] :seedling: fix rangeValCopy linter issues (#3735) Adding the Required field to PullRequestReviewRule made BranchRef slightly too big for the linter. This code isn't highly used, so just ignoring the inefficiency for now. Not sure why the staticcheck linter started complaining about the date error checking, but fixed it while I was here. Signed-off-by: Spencer Schrock --- cron/internal/format/json_raw_results.go | 2 +- pkg/json_raw_results.go | 2 +- pkg/json_test.go | 8 ++++---- pkg/scorecard_result_test.go | 9 ++++----- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/cron/internal/format/json_raw_results.go b/cron/internal/format/json_raw_results.go index 1a2d6e64331..7fda0f62dc5 100644 --- a/cron/internal/format/json_raw_results.go +++ b/cron/internal/format/json_raw_results.go @@ -201,9 +201,9 @@ func addDependencyUpdateToolRawResults(r *jsonScorecardRawResult, return nil } -//nolint:unparam func addBranchProtectionRawResults(r *jsonScorecardRawResult, bp *checker.BranchProtectionsData) error { r.Results.BranchProtections = []jsonBranchProtection{} + //nolint:gocritic for _, v := range bp.Branches { var bp *jsonBranchProtectionSettings if v.Protected != nil && *v.Protected { diff --git a/pkg/json_raw_results.go b/pkg/json_raw_results.go index 5d63cacfec8..cb4fbf354ff 100644 --- a/pkg/json_raw_results.go +++ b/pkg/json_raw_results.go @@ -703,9 +703,9 @@ func (r *jsonScorecardRawResult) addDependencyUpdateToolRawResults(dut *checker. return nil } -//nolint:unparam func (r *jsonScorecardRawResult) addBranchProtectionRawResults(bp *checker.BranchProtectionsData) error { branches := []jsonBranchProtection{} + //nolint:gocritic for _, v := range bp.Branches { var bp *jsonBranchProtectionSettings if v.Protected != nil && *v.Protected { diff --git a/pkg/json_test.go b/pkg/json_test.go index 7391cfb1efd..0c41079f74b 100644 --- a/pkg/json_test.go +++ b/pkg/json_test.go @@ -74,11 +74,11 @@ func TestJSONOutput(t *testing.T) { scorecardCommit := "ccbc59901773ab4c051dfcea0cc4201a1567abdd" scorecardVersion := "1.2.3" repoName := "org/name" - date, e := time.Parse(time.RFC3339, "2023-03-02T10:30:43-06:00") - t.Logf("date: %v", date) - if e != nil { - panic(fmt.Errorf("time.Parse: %w", e)) + date, err := time.Parse(time.RFC3339, "2023-03-02T10:30:43-06:00") + if err != nil { + t.Fatalf("time.Parse: %v", err) } + t.Logf("date: %v", date) checkDocs := jsonMockDocRead() diff --git a/pkg/scorecard_result_test.go b/pkg/scorecard_result_test.go index 7d78aafa29c..79f14ea26ca 100644 --- a/pkg/scorecard_result_test.go +++ b/pkg/scorecard_result_test.go @@ -17,7 +17,6 @@ package pkg import ( "bytes" "encoding/json" - "fmt" "os" "testing" "time" @@ -33,11 +32,11 @@ import ( func mockScorecardResultCheck1(t *testing.T) *ScorecardResult { t.Helper() // Helper variables to mock Scorecard results - date, e := time.Parse(time.RFC3339, "2023-03-02T10:30:43-06:00") - t.Logf("date: %v", date) - if e != nil { - panic(fmt.Errorf("time.Parse: %w", e)) + date, err := time.Parse(time.RFC3339, "2023-03-02T10:30:43-06:00") + if err != nil { + t.Fatalf("time.Parse: %v", err) } + t.Logf("date: %v", date) return &ScorecardResult{ Repo: RepoInfo{ From d5900ed5497fb441992175f6045cc477eb885ffe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:40:44 +0000 Subject: [PATCH 48/51] :seedling: Bump github.com/go-git/go-git/v5 from 5.10.1 to 5.11.0 (#3723) Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.10.1 to 5.11.0. - [Release notes](https://github.com/go-git/go-git/releases) - [Commits](https://github.com/go-git/go-git/compare/v5.10.1...v5.11.0) --- updated-dependencies: - dependency-name: github.com/go-git/go-git/v5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a1fe32e529a..d92dbcf6ded 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.14 github.com/bombsimon/logrusr/v2 v2.0.1 github.com/bradleyfalzon/ghinstallation/v2 v2.8.0 - github.com/go-git/go-git/v5 v5.10.1 + github.com/go-git/go-git/v5 v5.11.0 github.com/go-logr/logr v1.3.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index 272d73498ce..5c9ce70e1b0 100644 --- a/go.sum +++ b/go.sum @@ -287,8 +287,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+ github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk= -github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= From f4bf574c8638b77a28d5403cb56b826bda83734b Mon Sep 17 00:00:00 2001 From: David E Worth Date: Mon, 18 Dec 2023 13:10:12 -0700 Subject: [PATCH 49/51] :book: fixup transposition typos in remediation package (#3734) Signed-off-by: Dave Worth --- remediation/remediations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/remediation/remediations.go b/remediation/remediations.go index 6d49e421280..3a737490099 100644 --- a/remediation/remediations.go +++ b/remediation/remediations.go @@ -61,7 +61,7 @@ func New(c *checker.CheckRequest) (*RemediationMetadata, error) { return &RemediationMetadata{Branch: branch, Repo: repo}, nil } -// CreateWorkflowPinningRemediation create remediaiton for pinninn GH Actions. +// CreateWorkflowPinningRemediation create remediation for pinning GH Actions. func (r *RemediationMetadata) CreateWorkflowPinningRemediation(filepath string) *rule.Remediation { return r.createWorkflowRemediation(filepath, "pin") } @@ -100,7 +100,7 @@ func (c CraneDigester) Digest(name string) (string, error) { return crane.Digest(name) } -// CreateDockerfilePinningRemediation create remediaiton for pinning Dockerfile images. +// CreateDockerfilePinningRemediation create remediation for pinning Dockerfile images. func CreateDockerfilePinningRemediation(dep *checker.Dependency, digester Digester) *rule.Remediation { name, ok := dockerImageName(dep) if !ok { From df7d88898f6bf483e5d84cd476eec80505785593 Mon Sep 17 00:00:00 2001 From: Allen Shearin Date: Mon, 18 Dec 2023 13:51:25 -0700 Subject: [PATCH 50/51] =?UTF-8?q?=F0=9F=8C=B1=20=20differentiate=20between?= =?UTF-8?q?=20refs=20and=20sha=20gitab=20(#3729)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: differentiate between refs and sha gitab listcheckrunsforref Signed-off-by: Allen Shearin * address pr comments Signed-off-by: Allen Shearin * style: move gitlab call to one line Signed-off-by: Allen Shearin * update gitlab api comments Signed-off-by: Allen Shearin --------- Signed-off-by: Allen Shearin --- clients/gitlabrepo/checkruns.go | 21 ++++++++++++++++----- clients/gitlabrepo/checkruns_test.go | 6 +++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/clients/gitlabrepo/checkruns.go b/clients/gitlabrepo/checkruns.go index 80f62546e11..0dbbf8c214b 100644 --- a/clients/gitlabrepo/checkruns.go +++ b/clients/gitlabrepo/checkruns.go @@ -16,12 +16,15 @@ package gitlabrepo import ( "fmt" + "regexp" "github.com/xanzy/go-gitlab" "github.com/ossf/scorecard/v4/clients" ) +var gitCommitHashRegex = regexp.MustCompile(`^[a-fA-F0-9]{40}$`) + type checkrunsHandler struct { glClient *gitlab.Client repourl *repoURL @@ -32,11 +35,19 @@ func (handler *checkrunsHandler) init(repourl *repoURL) { } func (handler *checkrunsHandler) listCheckRunsForRef(ref string) ([]clients.CheckRun, error) { - pipelines, _, err := handler.glClient.Pipelines.ListProjectPipelines( - handler.repourl.projectID, &gitlab.ListProjectPipelinesOptions{ - SHA: &ref, - ListOptions: gitlab.ListOptions{}, - }) + var options gitlab.ListProjectPipelinesOptions + + if gitCommitHashRegex.MatchString(ref) { + options.SHA = &ref + } else { + options.Ref = &ref + } + + // Notes for Gitlab ListProjectPipelines endpoint: + // Only full SHA works for SHA param, Short SHA does not work + // Branch names work for Ref Param, tags and SHAs do not work + // Reference: https://docs.gitlab.com/ee/api/pipelines.html#list-project-pipelines + pipelines, _, err := handler.glClient.Pipelines.ListProjectPipelines(handler.repourl.projectID, &options) if err != nil { return nil, fmt.Errorf("request for pipelines returned error: %w", err) } diff --git a/clients/gitlabrepo/checkruns_test.go b/clients/gitlabrepo/checkruns_test.go index c11ff2b5408..94921ead4be 100644 --- a/clients/gitlabrepo/checkruns_test.go +++ b/clients/gitlabrepo/checkruns_test.go @@ -29,12 +29,14 @@ func Test_CheckRuns(t *testing.T) { tests := []struct { name string responsePath string + ref string want []clients.CheckRun wantErr bool }{ { name: "valid checkruns", responsePath: "./testdata/valid-checkruns", + ref: "main", want: []clients.CheckRun{ { Status: "queued", @@ -47,11 +49,13 @@ func Test_CheckRuns(t *testing.T) { { name: "valid checkruns with zero results", responsePath: "./testdata/valid-checkruns-1", + ref: "eb94b618fb5865b26e80fdd8ae531b7a63ad851a", wantErr: false, }, { name: "failure fetching the checkruns", responsePath: "./testdata/invalid-checkruns-result", + ref: "main", wantErr: true, }, } @@ -77,7 +81,7 @@ func Test_CheckRuns(t *testing.T) { commitSHA: clients.HeadSHA, } handler.init(&repoURL) - got, err := handler.listCheckRunsForRef("main") + got, err := handler.listCheckRunsForRef(tt.ref) if (err != nil) != tt.wantErr { t.Fatalf("checkRuns error: %v, wantedErr: %t", err, tt.wantErr) } From 21bbe80ad6a2695640ae1d58ffccb1033c517430 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:38:43 -0500 Subject: [PATCH 51/51] :seedling: Bump golang.org/x/crypto from 0.16.0 to 0.17.0 (#3742) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0. - [Commits](https://github.com/golang/crypto/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d92dbcf6ded..bb5e4b98b92 100644 --- a/go.mod +++ b/go.mod @@ -172,7 +172,7 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.15.0 diff --git a/go.sum b/go.sum index 5c9ce70e1b0..30f30002dd5 100644 --- a/go.sum +++ b/go.sum @@ -832,8 +832,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=