Skip to content

Commit

Permalink
✨ SARIF 4: Add support to output SARIF format (#866)
Browse files Browse the repository at this point in the history
* draft1

* draft2

* draft

* draft 3

* typos

* unit tests

* fixes

* fixes

* related locs

* fixes

* version

* fixes

* linter/fix

* fixes

* linter

* gofmt -s
  • Loading branch information
laurentsimon committed Aug 23, 2021
1 parent d1de6cf commit 276155d
Show file tree
Hide file tree
Showing 16 changed files with 1,760 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,5 @@ jobs:
go env -w GOFLAGS=-mod=mod
make all
set -e
addlicense -ignore "**/script-empty.sh" -l apache -c 'Security Scorecard Authors' -v *
addlicense -ignore "**/script-empty.sh" -ignore "pkg/testdata/*" -l apache -c 'Security Scorecard Authors' -v *
git diff --exit-code
22 changes: 21 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ossf/scorecard/v2/checker"
"github.com/ossf/scorecard/v2/checks"
"github.com/ossf/scorecard/v2/clients/githubrepo"
docs "github.com/ossf/scorecard/v2/docs/checks"
sce "github.com/ossf/scorecard/v2/errors"
"github.com/ossf/scorecard/v2/pkg"
"github.com/ossf/scorecard/v2/repos"
Expand All @@ -57,6 +58,7 @@ var (
const (
formatCSV = "csv"
formatJSON = "json"
formatSarif = "sarif"
formatDefault = "default"
)

Expand All @@ -66,6 +68,11 @@ or ./scorecard --{npm,pypi,rubgems}=<package_name> [--checks=check1,...] [--show
Short: "Security Scorecards",
Long: "A program that shows security scorecard for an open source software.",
Run: func(cmd *cobra.Command, args []string) {
// UPGRADEv3: remove.
var v3 bool
if _, v3 = os.LookupEnv("SCORECARD_V3"); v3 {
fmt.Printf("**** Using SCORECARD_V3 code ***** \n\n")
}
cfg := zap.NewProductionConfig()
cfg.Level.SetLevel(*logLevel)
logger, err := cfg.Build()
Expand Down Expand Up @@ -158,6 +165,18 @@ or ./scorecard --{npm,pypi,rubgems}=<package_name> [--checks=check1,...] [--show
switch format {
case formatDefault:
err = repoResult.AsString(showDetails, *logLevel, os.Stdout)
case formatSarif:
if !v3 {
log.Fatalf("sarif not supported yet")
}
checkDocs, e := docs.Read()
if e != nil {
log.Fatalf("cannot read yaml file: %v", err)
}
// TODO: support config files and update checker.MaxResultScore.
// TODO: set version dynamically.
scorecardVersion := "1.2.3"
err = repoResult.AsSARIF(scorecardVersion, showDetails, *logLevel, os.Stdout, checkDocs, checker.MaxResultScore)
case formatCSV:
err = repoResult.AsCSV(showDetails, *logLevel, os.Stdout)
case formatJSON:
Expand Down Expand Up @@ -316,7 +335,8 @@ func init() {
rootCmd.Flags().StringVar(
&rubygems, "rubygems", "",
"rubygems package to check, given that the rubygems package has a GitHub repository")
rootCmd.Flags().StringVar(&format, "format", formatDefault, "output format. allowed values are [default, csv, json]")
rootCmd.Flags().StringVar(&format, "format", formatDefault,
"output format. allowed values are [default, sarif, html, json, csv]")
rootCmd.Flags().StringSliceVar(
&metaData, "metadata", []string{}, "metadata for the project. It can be multiple separated by commas")
rootCmd.Flags().BoolVar(&showDetails, "show-details", false, "show extra details about each check")
Expand Down
2 changes: 1 addition & 1 deletion cron/worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func processRequest(ctx context.Context,
}
log.Print(errorMsg)
}
result.Date = batchRequest.GetJobTime().AsTime().Format("2006-01-02")
result.Date = batchRequest.GetJobTime().AsTime()
if err := result.AsJSON(true /*showDetails*/, zapcore.InfoLevel, &buffer); err != nil {
return fmt.Errorf("error during result.AsJSON: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions docs/checks/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type Check struct {
Risk string `yaml:"-"`
Short string `yaml:"short"`
Description string `yaml:"description"`
Tags string `yaml:"tags"`
Remediation []string `yaml:"remediation"`
}

Expand Down
8 changes: 8 additions & 0 deletions docs/checks/validate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ func main() {
// nolint: goerr113
panic(fmt.Errorf("remediation for checkName: %s is empty", check))
}
if doc.Short == "" {
// nolint: goerr113
panic(fmt.Errorf("short for checkName: %s is empty", check))
}
if doc.Tags == "" {
// nolint: goerr113
panic(fmt.Errorf("tags for checkName: %s is empty", check))
}
}
for check := range m.Checks {
if _, exists := allChecks[check]; !exists {
Expand Down
83 changes: 83 additions & 0 deletions pkg/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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 (
"fmt"
"strings"

"go.uber.org/zap/zapcore"

"github.com/ossf/scorecard/v2/checker"
)

// TODO: Verify this works in GitHub's dashboard.
func textToHTML(s string) string {
return strings.ReplaceAll(s, "\n", "<br>")
}

func textToMarkdown(s string) string {
return strings.ReplaceAll(s, "\n", " ")
}

func detailsToString(details []checker.CheckDetail, logLevel zapcore.Level) (string, bool) {
// UPGRADEv2: change to make([]string, len(details))
// followed by sa[i] = instead of append.
var sa []string
for _, v := range details {
switch v.Msg.Version {
//nolint
case 3:
if v.Type == checker.DetailDebug && logLevel != zapcore.DebugLevel {
continue
}
switch {
case v.Msg.Path != "" && v.Msg.Offset != 0:
sa = append(sa, fmt.Sprintf("%s: %s: %s:%d", typeToString(v.Type), v.Msg.Text, v.Msg.Path, v.Msg.Offset))
case v.Msg.Path != "" && v.Msg.Offset == 0:
sa = append(sa, fmt.Sprintf("%s: %s: %s", typeToString(v.Type), v.Msg.Text, v.Msg.Path))
default:
sa = append(sa, fmt.Sprintf("%s: %s", typeToString(v.Type), v.Msg.Text))
}
default:
if v.Type == checker.DetailDebug && logLevel != zapcore.DebugLevel {
continue
}
sa = append(sa, fmt.Sprintf("%s: %s", typeToString(v.Type), v.Msg.Text))
}
}
return strings.Join(sa, "\n"), len(sa) > 0
}

func typeToString(cd checker.DetailType) string {
switch cd {
default:
panic("invalid detail")
case checker.DetailInfo:
return "Info"
case checker.DetailWarn:
return "Warn"
case checker.DetailDebug:
return "Debug"
}
}

func tagsAsList(tags string) []string {
l := strings.Split(tags, ",")
for i := range l {
l[i] = strings.TrimSpace(l[i])
}
return l
}
Loading

0 comments on commit 276155d

Please sign in to comment.