Skip to content

Commit

Permalink
Use Scorecard library entrypoint instead of Cobra hooking (#1423)
Browse files Browse the repository at this point in the history
* use new Scorecard entrypoint

Scorecard V5 released a new entrypoint, so make use of it instead of
hooking into the underlying Cobra CLI. This gives us more flexibility
when running Scorecard, such as writing the result to multiple formats.

Signed-off-by: Spencer Schrock <sschrock@google.com>

* add basic format tests

Signed-off-by: Spencer Schrock <sschrock@google.com>

* run go mod tidy to cleanup removed transitive deps

Signed-off-by: Spencer Schrock <sschrock@google.com>

* Apply suggestions from code review

Signed-off-by: Stephen Augustus <justaugustus@users.noreply.github.com>

---------

Signed-off-by: Spencer Schrock <sschrock@google.com>
Signed-off-by: Stephen Augustus <justaugustus@users.noreply.github.com>
Co-authored-by: Stephen Augustus <justaugustus@users.noreply.github.com>
  • Loading branch information
spencerschrock and justaugustus authored Aug 10, 2024
1 parent bf01931 commit d10a2ed
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 189 deletions.
143 changes: 0 additions & 143 deletions entrypoint/entrypoint.go

This file was deleted.

1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.2.1 // indirect
Expand Down
7 changes: 0 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,6 @@ github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms=
github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
Expand Down Expand Up @@ -861,7 +860,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
Expand All @@ -884,7 +882,6 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
Expand All @@ -909,7 +906,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
Expand All @@ -931,9 +927,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down Expand Up @@ -995,7 +989,6 @@ golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
Expand Down
88 changes: 88 additions & 0 deletions internal/scorecard/format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2024 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 scorecard

import (
"errors"
"fmt"
"io"
"os"
"strings"

"github.com/ossf/scorecard-action/options"
"github.com/ossf/scorecard/v5/docs/checks"
sclog "github.com/ossf/scorecard/v5/log"
"github.com/ossf/scorecard/v5/pkg/scorecard"
"github.com/ossf/scorecard/v5/policy"
)

const (
defaultScorecardPolicyFile = "/policy.yml"
)

var (
errNoResult = errors.New("must provide a result")
errUnknownFormat = errors.New("unknown result format")
)

// Format provides a wrapper around the Scorecard library's various formatting functions,
// converting our options into theirs.
func Format(result *scorecard.Result, opts *options.Options) error {
if result == nil {
return errNoResult
}

// write results to both stdout and result file
resultFile, err := os.Create(opts.GithubWorkspace + opts.InputResultsFile)
if err != nil {
return fmt.Errorf("creating result file: %w", err)
}
defer resultFile.Close()
writer := io.MultiWriter(resultFile, os.Stdout)

docs, err := checks.Read()
if err != nil {
return fmt.Errorf("read check docs: %w", err)
}

switch strings.ToLower(opts.InputResultsFormat) {
// sarif is considered the default format when unset
case "", "sarif":
if opts.ScorecardOpts.PolicyFile == "" {
opts.ScorecardOpts.PolicyFile = defaultScorecardPolicyFile
}
pol, err := policy.ParseFromFile(opts.ScorecardOpts.PolicyFile)
if err != nil {
return fmt.Errorf("parse policy file: %w", err)
}
err = result.AsSARIF(true, sclog.DefaultLevel, writer, docs, pol, opts.ScorecardOpts)
if err != nil {
return fmt.Errorf("format as sarif: %w", err)
}
case "json":
err = result.AsJSON2(writer, docs, &scorecard.AsJSON2ResultOption{
Details: true,
Annotations: false, // TODO
LogLevel: sclog.DefaultLevel,
})
if err != nil {
return fmt.Errorf("format as JSON: %w", err)
}
default:
return errUnknownFormat
}

return nil
}
84 changes: 84 additions & 0 deletions internal/scorecard/format_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2024 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 scorecard

import (
"bytes"
"os"
"testing"

"github.com/ossf/scorecard-action/options"
scopts "github.com/ossf/scorecard/v5/options"
"github.com/ossf/scorecard/v5/pkg/scorecard"
)

func TestFormat(t *testing.T) {
t.Parallel()
tests := []struct {
name, format string
pattern []byte
}{
{
name: "default is sarif",
format: "",
pattern: []byte("sarif-schema"),
},
{
name: "sarif format supported",
format: "sarif",
pattern: []byte("sarif-schema"),
},
{
name: "json format supported",
format: "json",
// This isn't quite as strong of a guarantee, but dont expect this to change
pattern: []byte(`"name":"github.com/foo/bar"`),
},
{
name: "format is case insensitive",
format: "SARIF",
pattern: []byte("sarif-schema"),
},
}
result := scorecard.Result{
Repo: scorecard.RepoInfo{
Name: "github.com/foo/bar",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
opts := options.Options{
InputResultsFile: t.TempDir() + "/results",
InputResultsFormat: tt.format,
ScorecardOpts: &scopts.Options{
PolicyFile: "../../policies/template.yml",
},
}
err := Format(&result, &opts)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
contents, err := os.ReadFile(opts.InputResultsFile)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !bytes.Contains(contents, tt.pattern) {
t.Errorf("Output didn't match expected pattern (%s)", tt.pattern)
}
})
}
}
Loading

0 comments on commit d10a2ed

Please sign in to comment.