-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
sarif.go
126 lines (109 loc) · 3.23 KB
/
sarif.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package sarif
import (
"encoding/json"
"fmt"
"io"
"os"
)
// Version is the version of Sarif to use
type Version string
// Version210 represents Version210 of Sarif
const (
Version210 Version = "2.1.0"
// @Deprecated - use Version210 instead
Version210RTM5 Version = "2.1.0-rtm.5"
)
var versions = map[Version]string{
Version210: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
// keeping this for backwards support but marked as deprecated
Version210RTM5: "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
}
// Report is the encapsulating type representing a Sarif Report
type Report struct {
PropertyBag
InlineExternalProperties []*ExternalProperties `json:"inlineExternalProperties,omitempty"`
Version string `json:"version"`
Schema string `json:"$schema,omitempty"`
Runs []*Run `json:"runs"`
}
// New Creates a new Report or returns an error
func New(version Version, includeSchema ...bool) (*Report, error) {
schema := ""
if len(includeSchema) == 0 || includeSchema[0] {
var err error
schema, err = getVersionSchema(version)
if err != nil {
return nil, err
}
}
return &Report{
Version: string(version),
Schema: schema,
Runs: []*Run{},
}, nil
}
// Open loads a Report from a file
func Open(filename string) (*Report, error) {
if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) {
return nil, fmt.Errorf("the provided file path doesn't have a file")
}
content, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("the provided filepath could not be opened. %w", err)
}
return FromBytes(content)
}
// FromString loads a Report from string content
func FromString(content string) (*Report, error) {
return FromBytes([]byte(content))
}
// FromBytes loads a Report from a byte array
func FromBytes(content []byte) (*Report, error) {
var report Report
if err := json.Unmarshal(content, &report); err != nil {
return nil, err
}
return &report, nil
}
// AddRun allows adding run information to the current report
func (sarif *Report) AddRun(run *Run) {
sarif.Runs = append(sarif.Runs, run)
}
func getVersionSchema(version Version) (string, error) {
for ver, schema := range versions {
if ver == version {
return schema, nil
}
}
return "", fmt.Errorf("version [%s] is not supported", version)
}
// WriteFile will write the report to a file using a pretty formatter
func (sarif *Report) WriteFile(filename string) error {
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer func() { _ = file.Close() }()
return sarif.PrettyWrite(file)
}
// Write writes the JSON as a string with no formatting
func (sarif *Report) Write(w io.Writer) error {
for _, run := range sarif.Runs {
run.DedupeArtifacts()
}
marshal, err := json.Marshal(sarif)
if err != nil {
return err
}
_, err = w.Write(marshal)
return err
}
// PrettyWrite writes the JSON output with indentation
func (sarif *Report) PrettyWrite(w io.Writer) error {
marshal, err := json.MarshalIndent(sarif, "", " ")
if err != nil {
return err
}
_, err = w.Write(marshal)
return err
}