mirror of
https://github.com/ossf/scorecard.git
synced 2024-09-19 13:07:17 +03:00
✨ Add hash to results (JSON, SARIF) (#892)
* add hash to result * add json file
This commit is contained in:
parent
6403eb1382
commit
ad134ac30d
108
pkg/json.go
Normal file
108
pkg/json.go
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2021 Security 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"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/ossf/scorecard/v2/checker"
|
||||
sce "github.com/ossf/scorecard/v2/errors"
|
||||
)
|
||||
|
||||
//nolint
|
||||
type jsonCheckResultV2 struct {
|
||||
Details []string
|
||||
Score int
|
||||
Reason string
|
||||
Name string
|
||||
}
|
||||
|
||||
type jsonScorecardResultV2 struct {
|
||||
Repo string
|
||||
Date string
|
||||
Commit string
|
||||
Checks []jsonCheckResultV2
|
||||
Metadata []string
|
||||
}
|
||||
|
||||
// AsJSON outputs the result in JSON format with a newline at the end.
|
||||
// If called on []ScorecardResult will create NDJson formatted output.
|
||||
// UPGRADEv2: will be removed.
|
||||
func (r *ScorecardResult) AsJSON(showDetails bool, logLevel zapcore.Level, writer io.Writer) error {
|
||||
encoder := json.NewEncoder(writer)
|
||||
if showDetails {
|
||||
if err := encoder.Encode(r); err != nil {
|
||||
//nolint:wrapcheck
|
||||
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
out := ScorecardResult{
|
||||
Repo: r.Repo,
|
||||
Date: r.Date,
|
||||
Metadata: r.Metadata,
|
||||
}
|
||||
// UPGRADEv2: remove nolint after ugrade.
|
||||
//nolint
|
||||
for _, checkResult := range r.Checks {
|
||||
tmpResult := checker.CheckResult{
|
||||
Name: checkResult.Name,
|
||||
Pass: checkResult.Pass,
|
||||
Confidence: checkResult.Confidence,
|
||||
}
|
||||
out.Checks = append(out.Checks, tmpResult)
|
||||
}
|
||||
if err := encoder.Encode(out); err != nil {
|
||||
//nolint:wrapcheck
|
||||
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AsJSON2 exports results as JSON for new detail format.
|
||||
func (r *ScorecardResult) AsJSON2(showDetails bool, logLevel zapcore.Level, writer io.Writer) error {
|
||||
encoder := json.NewEncoder(writer)
|
||||
|
||||
out := jsonScorecardResultV2{
|
||||
Repo: r.Repo,
|
||||
Date: r.Date.Format("2006-01-02"),
|
||||
Commit: r.CommitSHA,
|
||||
Metadata: r.Metadata,
|
||||
}
|
||||
|
||||
//nolint
|
||||
for _, checkResult := range r.Checks {
|
||||
tmpResult := jsonCheckResultV2{
|
||||
Name: checkResult.Name,
|
||||
Reason: checkResult.Reason,
|
||||
Score: checkResult.Score,
|
||||
}
|
||||
if showDetails {
|
||||
for _, d := range checkResult.Details2 {
|
||||
tmpResult.Details = append(tmpResult.Details, d.Msg.Text)
|
||||
}
|
||||
}
|
||||
out.Checks = append(out.Checks, tmpResult)
|
||||
}
|
||||
if err := encoder.Encode(out); err != nil {
|
||||
//nolint:wrapcheck
|
||||
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
@ -327,7 +327,7 @@ func scoreToLevel(minScore, score int) string {
|
||||
}
|
||||
}
|
||||
|
||||
func createSARIFHeader(url, category, name, version string, t time.Time) sarif210 {
|
||||
func createSARIFHeader(url, category, name, version, commit string, t time.Time) sarif210 {
|
||||
return sarif210{
|
||||
Schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
||||
Version: "2.1.0",
|
||||
@ -345,7 +345,7 @@ func createSARIFHeader(url, category, name, version string, t time.Time) sarif21
|
||||
// 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.
|
||||
ID: fmt.Sprintf("%s/%s/%s", category, name, t.Format(time.RFC822Z)),
|
||||
ID: fmt.Sprintf("%s/%s/%s", category, name, fmt.Sprintf("%s-%s", commit, t.Format(time.RFC822Z))),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -397,7 +397,7 @@ func (r *ScorecardResult) AsSARIF(version string, showDetails bool, logLevel zap
|
||||
// see https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/sarif-support-for-code-scanning#supported-sarif-output-file-properties,
|
||||
// https://github.com/microsoft/sarif-tutorials.
|
||||
sarif := createSARIFHeader("https://github.com/ossf/scorecard",
|
||||
"supply-chain", "scorecard", version, r.Date)
|
||||
"supply-chain", "scorecard", version, r.CommitSHA, r.Date)
|
||||
results := []result{}
|
||||
rules := []rule{}
|
||||
|
||||
|
@ -39,6 +39,7 @@ func TestSATIFOutput(t *testing.T) {
|
||||
Tags string `yaml:"tags"`
|
||||
}
|
||||
|
||||
commit := "68bc59901773ab4c051dfcea0cc4201a1567ab32"
|
||||
date, e := time.Parse(time.RFC822Z, "17 Aug 21 18:57 +0000")
|
||||
if e != nil {
|
||||
panic(fmt.Errorf("time.Parse: %w", e))
|
||||
@ -71,8 +72,9 @@ func TestSATIFOutput(t *testing.T) {
|
||||
},
|
||||
},
|
||||
result: ScorecardResult{
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
CommitSHA: commit,
|
||||
Checks: []checker.CheckResult{
|
||||
{
|
||||
Details2: []checker.CheckDetail{
|
||||
@ -115,8 +117,9 @@ func TestSATIFOutput(t *testing.T) {
|
||||
},
|
||||
},
|
||||
result: ScorecardResult{
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
CommitSHA: commit,
|
||||
Checks: []checker.CheckResult{
|
||||
{
|
||||
Details2: []checker.CheckDetail{
|
||||
@ -172,8 +175,9 @@ func TestSATIFOutput(t *testing.T) {
|
||||
},
|
||||
},
|
||||
result: ScorecardResult{
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
CommitSHA: commit,
|
||||
Checks: []checker.CheckResult{
|
||||
{
|
||||
Details2: []checker.CheckDetail{
|
||||
@ -282,8 +286,9 @@ func TestSATIFOutput(t *testing.T) {
|
||||
},
|
||||
},
|
||||
result: ScorecardResult{
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
CommitSHA: commit,
|
||||
Checks: []checker.CheckResult{
|
||||
{
|
||||
Details2: []checker.CheckDetail{
|
||||
@ -377,8 +382,9 @@ func TestSATIFOutput(t *testing.T) {
|
||||
},
|
||||
},
|
||||
result: ScorecardResult{
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
CommitSHA: commit,
|
||||
Checks: []checker.CheckResult{
|
||||
{
|
||||
Details2: []checker.CheckDetail{
|
||||
@ -419,8 +425,9 @@ func TestSATIFOutput(t *testing.T) {
|
||||
},
|
||||
},
|
||||
result: ScorecardResult{
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
Repo: "repo not used",
|
||||
Date: date,
|
||||
CommitSHA: commit,
|
||||
Checks: []checker.CheckResult{
|
||||
{
|
||||
Details2: []checker.CheckDetail{
|
||||
|
@ -92,9 +92,20 @@ func RunScorecards(ctx context.Context,
|
||||
return ScorecardResult{}, err
|
||||
}
|
||||
|
||||
commits, err := repoClient.ListCommits()
|
||||
if err != nil {
|
||||
//nolint:wrapcheck
|
||||
return ScorecardResult{}, err
|
||||
}
|
||||
|
||||
if len(commits) == 0 {
|
||||
//nolint:wrapcheck
|
||||
return ScorecardResult{}, sce.Create(sce.ErrScorecardInternal, "no commits found")
|
||||
}
|
||||
ret := ScorecardResult{
|
||||
Repo: repo.URL(),
|
||||
Date: time.Now(),
|
||||
Repo: repo.URL(),
|
||||
Date: time.Now(),
|
||||
CommitSHA: commits[0].SHA,
|
||||
}
|
||||
resultsCh := make(chan checker.CheckResult)
|
||||
go runEnabledChecks(ctx, repo, checksToRun, repoClient,
|
||||
|
@ -16,7 +16,6 @@ package pkg
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -33,90 +32,11 @@ import (
|
||||
|
||||
// ScorecardResult struct is returned on a successful Scorecard run.
|
||||
type ScorecardResult struct {
|
||||
Repo string
|
||||
Date time.Time
|
||||
Checks []checker.CheckResult
|
||||
Metadata []string
|
||||
}
|
||||
|
||||
//nolint
|
||||
type jsonCheckResultV2 struct {
|
||||
Details []string
|
||||
Score int
|
||||
Reason string
|
||||
Name string
|
||||
}
|
||||
|
||||
type jsonScorecardResultV2 struct {
|
||||
Repo string
|
||||
Date string
|
||||
Checks []jsonCheckResultV2
|
||||
Metadata []string
|
||||
}
|
||||
|
||||
// AsJSON outputs the result in JSON format with a newline at the end.
|
||||
// If called on []ScorecardResult will create NDJson formatted output.
|
||||
// UPGRADEv2: will be removed.
|
||||
func (r *ScorecardResult) AsJSON(showDetails bool, logLevel zapcore.Level, writer io.Writer) error {
|
||||
encoder := json.NewEncoder(writer)
|
||||
if showDetails {
|
||||
if err := encoder.Encode(r); err != nil {
|
||||
//nolint:wrapcheck
|
||||
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
out := ScorecardResult{
|
||||
Repo: r.Repo,
|
||||
Date: r.Date,
|
||||
Metadata: r.Metadata,
|
||||
}
|
||||
// UPGRADEv2: remove nolint after ugrade.
|
||||
//nolint
|
||||
for _, checkResult := range r.Checks {
|
||||
tmpResult := checker.CheckResult{
|
||||
Name: checkResult.Name,
|
||||
Pass: checkResult.Pass,
|
||||
Confidence: checkResult.Confidence,
|
||||
}
|
||||
out.Checks = append(out.Checks, tmpResult)
|
||||
}
|
||||
if err := encoder.Encode(out); err != nil {
|
||||
//nolint:wrapcheck
|
||||
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AsJSON2 exports results as JSON for new detail format.
|
||||
func (r *ScorecardResult) AsJSON2(showDetails bool, logLevel zapcore.Level, writer io.Writer) error {
|
||||
encoder := json.NewEncoder(writer)
|
||||
|
||||
out := jsonScorecardResultV2{
|
||||
Repo: r.Repo,
|
||||
Date: r.Date.Format("2006-01-02"),
|
||||
Metadata: r.Metadata,
|
||||
}
|
||||
|
||||
//nolint
|
||||
for _, checkResult := range r.Checks {
|
||||
tmpResult := jsonCheckResultV2{
|
||||
Name: checkResult.Name,
|
||||
Reason: checkResult.Reason,
|
||||
Score: checkResult.Score,
|
||||
}
|
||||
if showDetails {
|
||||
for _, d := range checkResult.Details2 {
|
||||
tmpResult.Details = append(tmpResult.Details, d.Msg.Text)
|
||||
}
|
||||
}
|
||||
out.Checks = append(out.Checks, tmpResult)
|
||||
}
|
||||
if err := encoder.Encode(out); err != nil {
|
||||
//nolint:wrapcheck
|
||||
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
|
||||
}
|
||||
return nil
|
||||
Repo string
|
||||
Date time.Time
|
||||
CommitSHA string
|
||||
Checks []checker.CheckResult
|
||||
Metadata []string
|
||||
}
|
||||
|
||||
// AsCSV outputs ScorecardResult in CSV format.
|
||||
|
2
pkg/testdata/check1.sarif
vendored
2
pkg/testdata/check1.sarif
vendored
@ -4,7 +4,7 @@
|
||||
"runs": [
|
||||
{
|
||||
"automationDetails": {
|
||||
"id": "supply-chain/scorecard/17 Aug 21 18:57 +0000"
|
||||
"id": "supply-chain/scorecard/68bc59901773ab4c051dfcea0cc4201a1567ab32-17 Aug 21 18:57 +0000"
|
||||
},
|
||||
"tool": {
|
||||
"driver": {
|
||||
|
2
pkg/testdata/check2.sarif
vendored
2
pkg/testdata/check2.sarif
vendored
@ -4,7 +4,7 @@
|
||||
"runs": [
|
||||
{
|
||||
"automationDetails": {
|
||||
"id": "supply-chain/scorecard/17 Aug 21 18:57 +0000"
|
||||
"id": "supply-chain/scorecard/68bc59901773ab4c051dfcea0cc4201a1567ab32-17 Aug 21 18:57 +0000"
|
||||
},
|
||||
"tool": {
|
||||
"driver": {
|
||||
|
2
pkg/testdata/check3.sarif
vendored
2
pkg/testdata/check3.sarif
vendored
@ -4,7 +4,7 @@
|
||||
"runs": [
|
||||
{
|
||||
"automationDetails": {
|
||||
"id": "supply-chain/scorecard/17 Aug 21 18:57 +0000"
|
||||
"id": "supply-chain/scorecard/68bc59901773ab4c051dfcea0cc4201a1567ab32-17 Aug 21 18:57 +0000"
|
||||
},
|
||||
"tool": {
|
||||
"driver": {
|
||||
|
2
pkg/testdata/check4.sarif
vendored
2
pkg/testdata/check4.sarif
vendored
@ -4,7 +4,7 @@
|
||||
"runs": [
|
||||
{
|
||||
"automationDetails": {
|
||||
"id": "supply-chain/scorecard/17 Aug 21 18:57 +0000"
|
||||
"id": "supply-chain/scorecard/68bc59901773ab4c051dfcea0cc4201a1567ab32-17 Aug 21 18:57 +0000"
|
||||
},
|
||||
"tool": {
|
||||
"driver": {
|
||||
|
2
pkg/testdata/check5.sarif
vendored
2
pkg/testdata/check5.sarif
vendored
@ -4,7 +4,7 @@
|
||||
"runs": [
|
||||
{
|
||||
"automationDetails": {
|
||||
"id": "supply-chain/scorecard/17 Aug 21 18:57 +0000"
|
||||
"id": "supply-chain/scorecard/68bc59901773ab4c051dfcea0cc4201a1567ab32-17 Aug 21 18:57 +0000"
|
||||
},
|
||||
"tool": {
|
||||
"driver": {
|
||||
|
2
pkg/testdata/check6.sarif
vendored
2
pkg/testdata/check6.sarif
vendored
@ -4,7 +4,7 @@
|
||||
"runs": [
|
||||
{
|
||||
"automationDetails": {
|
||||
"id": "supply-chain/scorecard/17 Aug 21 18:57 +0000"
|
||||
"id": "supply-chain/scorecard/68bc59901773ab4c051dfcea0cc4201a1567ab32-17 Aug 21 18:57 +0000"
|
||||
},
|
||||
"tool": {
|
||||
"driver": {
|
||||
|
Loading…
Reference in New Issue
Block a user