diff --git a/checker/raw_result.go b/checker/raw_result.go index 37dfcbd3e4f..621c84eb8ad 100644 --- a/checker/raw_result.go +++ b/checker/raw_result.go @@ -43,6 +43,11 @@ type RawResults struct { LicenseResults LicenseData TokenPermissionsResults TokenPermissionsData CITestResults CITestData + Metadata MetadataData +} + +type MetadataData struct { + Metadata map[string]string } type RevisionCIInfo struct { diff --git a/pkg/json_probe_results.go b/pkg/json_probe_results.go new file mode 100644 index 00000000000..633d39a47d4 --- /dev/null +++ b/pkg/json_probe_results.go @@ -0,0 +1,56 @@ +// 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 pkg + +import ( + "encoding/json" + "fmt" + "io" + + sce "github.com/ossf/scorecard/v4/errors" + "github.com/ossf/scorecard/v4/finding" +) + +// JSONScorecardProbeResult exports results as JSON for flat findings without checks. +// +//nolint:govet +type JSONScorecardProbeResult struct { + Date string `json:"date"` + Repo jsonRepoV2 `json:"repo"` + Scorecard jsonScorecardV2 `json:"scorecard"` + Findings []finding.Finding `json:"findings"` +} + +func (r *ScorecardResult) AsPJSON(writer io.Writer) error { + encoder := json.NewEncoder(writer) + out := JSONScorecardProbeResult{ + Repo: jsonRepoV2{ + Name: r.Repo.Name, + Commit: r.Repo.CommitSHA, + }, + Scorecard: jsonScorecardV2{ + Version: r.Scorecard.Version, + Commit: r.Scorecard.CommitSHA, + }, + Date: r.Date.Format("2006-01-02"), + Findings: r.Findings, + } + + if err := encoder.Encode(out); err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err)) + } + + return nil +} diff --git a/pkg/scorecard.go b/pkg/scorecard.go index dbf7ef570c9..d44976bf8a7 100644 --- a/pkg/scorecard.go +++ b/pkg/scorecard.go @@ -19,6 +19,8 @@ import ( "context" "errors" "fmt" + "os" + "strings" "sync" "time" @@ -27,6 +29,10 @@ import ( "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/options" + "github.com/ossf/scorecard/v4/probes" + "github.com/ossf/scorecard/v4/probes/zrunner" ) func runEnabledChecks(ctx context.Context, @@ -102,6 +108,15 @@ func RunScorecard(ctx context.Context, if err != nil || commitSHA == "" { return ScorecardResult{}, err } + defaultBranch, err := repoClient.GetDefaultBranchName() + if err != nil { + if !errors.Is(err, clients.ErrUnsupportedFeature) { + return ScorecardResult{}, + sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("GetDefaultBranchName:%v", err.Error())) + } + defaultBranch = "unknown" + } + versionInfo := version.GetVersionInfo() ret := ScorecardResult{ Repo: RepoInfo{ @@ -115,11 +130,42 @@ func RunScorecard(ctx context.Context, Date: time.Now(), } resultsCh := make(chan checker.CheckResult) - go runEnabledChecks(ctx, repo, &ret.RawResults, checksToRun, repoClient, ossFuzzRepoClient, + + // Set metadata for all checks to use. This is necessary + // to create remediations from the probe yaml files. + ret.RawResults.Metadata.Metadata = map[string]string{ + "repository.host": repo.Host(), + "repository.name": strings.TrimPrefix(repo.URI(), repo.Host()+"/"), + "repository.uri": repo.URI(), + "repository.sha1": commitSHA, + "repository.defaultBranch": defaultBranch, + } + + go runEnabledChecks(ctx, repo, &ret.RawResults, checksToRun, + repoClient, ossFuzzRepoClient, ciiClient, vulnsClient, resultsCh) for result := range resultsCh { ret.Checks = append(ret.Checks, result) } + + if value, _ := os.LookupEnv(options.EnvVarScorecardExperimental); value == "1" { + // Run the probes. + var findings []finding.Finding + // TODO(#3049): only run the probes for checks. + // NOTE: We will need separate functions to support: + // - `--probes X,Y` + // - `--check-definitions-file path/to/config.yml + // NOTE: we discard the returned error because the errors are + // already cotained in the findings and we want to return the findings + // to users. + // See https://github.com/ossf/scorecard/blob/main/probes/zrunner/runner.go#L34-L45. + // Note: we discard the error because each probe's error is reported within + // the probe and we don't want the entire scorecard run to fail if a single error + // is encountered. + //nolint:errcheck + findings, _ = zrunner.Run(&ret.RawResults, probes.All) + ret.Findings = findings + } return ret, nil } diff --git a/pkg/scorecard_result.go b/pkg/scorecard_result.go index 2fd0c67e4fb..c30167c5293 100644 --- a/pkg/scorecard_result.go +++ b/pkg/scorecard_result.go @@ -25,6 +25,7 @@ import ( "github.com/ossf/scorecard/v4/checker" "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" @@ -50,6 +51,7 @@ type ScorecardResult struct { Scorecard ScorecardInfo Checks []checker.CheckResult RawResults checker.RawResults + Findings []finding.Finding Metadata []string } @@ -119,6 +121,8 @@ func FormatResults( err = results.AsJSON2(opts.ShowDetails, log.ParseLevel(opts.LogLevel), doc, os.Stdout) case options.FormatFJSON: err = results.AsFJSON(opts.ShowDetails, log.ParseLevel(opts.LogLevel), doc, os.Stdout) + case options.FormatPJSON: + err = results.AsPJSON(os.Stdout) case options.FormatRaw: err = results.AsRawJSON(os.Stdout) default: diff --git a/probes/toolDependabotInstalled/impl.go b/probes/toolDependabotInstalled/impl.go index 1ca92087e10..d89ba6c9140 100644 --- a/probes/toolDependabotInstalled/impl.go +++ b/probes/toolDependabotInstalled/impl.go @@ -1,4 +1,4 @@ -// Copyright 2022 OpenSSF Scorecard Authors +// 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. diff --git a/probes/toolPyUpInstalled/impl.go b/probes/toolPyUpInstalled/impl.go index 41c58db88a1..42adb82685d 100644 --- a/probes/toolPyUpInstalled/impl.go +++ b/probes/toolPyUpInstalled/impl.go @@ -1,4 +1,4 @@ -// Copyright 2022 OpenSSF Scorecard Authors +// 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. diff --git a/probes/toolRenovateInstalled/impl.go b/probes/toolRenovateInstalled/impl.go index a35f91662cc..1c3d0b91161 100644 --- a/probes/toolRenovateInstalled/impl.go +++ b/probes/toolRenovateInstalled/impl.go @@ -1,4 +1,4 @@ -// Copyright 2022 OpenSSF Scorecard Authors +// 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. diff --git a/probes/toolSonatypeLiftInstalled/impl.go b/probes/toolSonatypeLiftInstalled/impl.go index a7c258fb9e8..98d0363ae72 100644 --- a/probes/toolSonatypeLiftInstalled/impl.go +++ b/probes/toolSonatypeLiftInstalled/impl.go @@ -1,4 +1,4 @@ -// Copyright 2022 OpenSSF Scorecard Authors +// 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.