Skip to content

Commit ad5a6f8

Browse files
author
Maceo Thompson
committed
internal/openvex: add handler
updates golang/go#62486 Change-Id: Ib1cd9281cf33fb84a8a3c0f3e7523cfb8d93e677 Reviewed-on: https://go-review.googlesource.com/c/vuln/+/575858 Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent b6af818 commit ad5a6f8

File tree

7 files changed

+206
-7
lines changed

7 files changed

+206
-7
lines changed

cmd/govulncheck/testdata/common/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
{
3636
"pattern": "\"go_version\": \"go[^\\s\"]*\"",
3737
"replace": "\"go_version\": \"go1.18\""
38+
},
39+
{
40+
"pattern": "\"timestamp\": (.*),",
41+
"replace": "\"timestamp\": \"2024-01-01T00:00:00\","
3842
}
3943
]
4044
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#####
2+
# Test basic binary scanning with vex output
3+
$ govulncheck -format openvex -mode binary ${common_vuln_binary}
4+
{
5+
"@context": "https://openvex.dev/ns/v0.2.0",
6+
"@id": "govulncheckVEX",
7+
"author": "Unknown Author",
8+
"timestamp": "2024-01-01T00:00:00",
9+
"version": 1,
10+
"tooling": "https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#####
2+
# Test vex json output
3+
$ govulncheck -C ${moddir}/vuln -format openvex ./...
4+
{
5+
"@context": "https://openvex.dev/ns/v0.2.0",
6+
"@id": "govulncheckVEX",
7+
"author": "Unknown Author",
8+
"timestamp": "2024-01-01T00:00:00",
9+
"version": 1,
10+
"tooling": "https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck"
11+
}

internal/openvex/handler.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package openvex
6+
7+
import (
8+
"encoding/json"
9+
"io"
10+
"time"
11+
12+
"golang.org/x/vuln/internal/govulncheck"
13+
"golang.org/x/vuln/internal/osv"
14+
)
15+
16+
type findingLevel int
17+
18+
const (
19+
invalid findingLevel = iota
20+
required
21+
imported
22+
called
23+
)
24+
25+
type handler struct {
26+
w io.Writer
27+
cfg *govulncheck.Config
28+
osvs map[string]*osv.Entry
29+
levels map[string]findingLevel
30+
}
31+
32+
func NewHandler(w io.Writer) *handler {
33+
return &handler{
34+
w: w,
35+
osvs: make(map[string]*osv.Entry),
36+
levels: make(map[string]findingLevel),
37+
}
38+
}
39+
40+
func (h *handler) Config(cfg *govulncheck.Config) error {
41+
h.cfg = cfg
42+
return nil
43+
}
44+
45+
func (h *handler) Progress(progress *govulncheck.Progress) error {
46+
return nil
47+
}
48+
49+
func (h *handler) OSV(e *osv.Entry) error {
50+
h.osvs[e.ID] = e
51+
return nil
52+
}
53+
54+
// foundAtLevel returns the level at which a specific finding is present in the
55+
// scanned product.
56+
func foundAtLevel(f *govulncheck.Finding) findingLevel {
57+
frame := f.Trace[0]
58+
if frame.Function != "" {
59+
return called
60+
}
61+
if frame.Package != "" {
62+
return imported
63+
}
64+
return required
65+
}
66+
67+
func (h *handler) Finding(f *govulncheck.Finding) error {
68+
fLevel := foundAtLevel(f)
69+
if fLevel > h.levels[f.OSV] {
70+
h.levels[f.OSV] = fLevel
71+
}
72+
return nil
73+
}
74+
75+
// Flush is used to print the vex json to w.
76+
// This is needed as vex is not streamed.
77+
func (h *handler) Flush() error {
78+
doc := toVex()
79+
out, err := json.MarshalIndent(doc, "", " ")
80+
if err != nil {
81+
return err
82+
}
83+
_, err = h.w.Write(out)
84+
return err
85+
}
86+
87+
func toVex() Document {
88+
doc := Document{
89+
ID: "govulncheckVEX", // TODO: create hash from document for ID
90+
Context: ContextURI,
91+
Author: DefaultAuthor,
92+
Timestamp: time.Now().UTC(),
93+
Version: 1,
94+
Tooling: Tooling,
95+
//TODO: Add statements
96+
}
97+
return doc
98+
}

internal/openvex/handler_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package openvex
6+
7+
import (
8+
"testing"
9+
10+
"golang.org/x/vuln/internal/govulncheck"
11+
)
12+
13+
func TestFinding(t *testing.T) {
14+
const id1 = "ID1"
15+
tests := []struct {
16+
name string
17+
id string
18+
findings []*govulncheck.Finding
19+
want findingLevel
20+
}{
21+
{
22+
name: "multiple",
23+
id: id1,
24+
findings: []*govulncheck.Finding{
25+
{
26+
OSV: id1,
27+
Trace: []*govulncheck.Frame{
28+
{
29+
Module: "mod",
30+
Package: "pkg",
31+
},
32+
},
33+
},
34+
{
35+
OSV: id1,
36+
Trace: []*govulncheck.Frame{
37+
{
38+
Module: "mod",
39+
Package: "pkg",
40+
Function: "func",
41+
},
42+
},
43+
},
44+
{
45+
OSV: id1,
46+
Trace: []*govulncheck.Frame{
47+
{
48+
Module: "mod",
49+
},
50+
},
51+
},
52+
},
53+
want: called,
54+
},
55+
}
56+
for _, tt := range tests {
57+
t.Run(tt.name, func(t *testing.T) {
58+
h := NewHandler(nil)
59+
for _, f := range tt.findings {
60+
if err := h.Finding(f); err != nil {
61+
t.Errorf("handler.Finding() error = %v", err)
62+
}
63+
}
64+
got := h.levels[tt.id]
65+
if got != tt.want {
66+
t.Errorf("want %v; got %v", tt.want, got)
67+
}
68+
})
69+
}
70+
}

internal/scan/flags.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,18 @@ func (v ShowFlag) Update(h *TextHandler) {
236236
type FormatFlag string
237237

238238
const (
239-
formatUnset = ""
240-
formatJSON = "json"
241-
formatText = "text"
242-
formatSarif = "sarif"
239+
formatUnset = ""
240+
formatJSON = "json"
241+
formatText = "text"
242+
formatSarif = "sarif"
243+
formatOpenVEX = "openvex"
243244
)
244245

245246
var supportedFormats = map[string]bool{
246-
formatJSON: true,
247-
formatText: true,
248-
formatSarif: true,
247+
formatJSON: true,
248+
formatText: true,
249+
formatSarif: true,
250+
formatOpenVEX: true,
249251
}
250252

251253
func (f *FormatFlag) Get() interface{} { return *f }

internal/scan/run.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"golang.org/x/telemetry/counter"
1919
"golang.org/x/vuln/internal/client"
2020
"golang.org/x/vuln/internal/govulncheck"
21+
"golang.org/x/vuln/internal/openvex"
2122
"golang.org/x/vuln/internal/sarif"
2223
)
2324

@@ -42,6 +43,8 @@ func RunGovulncheck(ctx context.Context, env []string, r io.Reader, stdout io.Wr
4243
handler = govulncheck.NewJSONHandler(stdout)
4344
case formatSarif:
4445
handler = sarif.NewHandler(stdout)
46+
case formatOpenVEX:
47+
handler = openvex.NewHandler(stdout)
4548
default:
4649
th := NewTextHandler(stdout)
4750
cfg.show.Update(th)

0 commit comments

Comments
 (0)