-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsarif.go
More file actions
145 lines (126 loc) · 3.41 KB
/
Copy pathsarif.go
File metadata and controls
145 lines (126 loc) · 3.41 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package sarif
import (
"bytes"
"embed"
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"sync"
"github.com/santhosh-tekuri/jsonschema/v6"
)
//go:embed schema/sarif-schema-2.1.0.json
var schemaFS embed.FS
const schemaPath = "schema/sarif-schema-2.1.0.json"
var (
compiledSchema *jsonschema.Schema
compiledSchemaErr error
compiledSchemaOnce sync.Once
)
// Load reads a SARIF log from path.
func Load(path string) (*Log, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("load sarif: %w", err)
}
return Parse(data)
}
// Parse decodes a SARIF log from JSON.
func Parse(data []byte) (*Log, error) {
var log Log
if err := json.Unmarshal(data, &log); err != nil {
return nil, fmt.Errorf("parse sarif: %w", err)
}
return &log, nil
}
// Marshal encodes a SARIF log to JSON.
func Marshal(log *Log, pretty bool) ([]byte, error) {
if pretty {
return json.MarshalIndent(log, "", " ")
}
return json.Marshal(log)
}
// Dump writes a SARIF log to w.
func Dump(log *Log, w io.Writer, pretty bool) error {
data, err := Marshal(log, pretty)
if err != nil {
return fmt.Errorf("dump sarif: %w", err)
}
if _, err := w.Write(data); err != nil {
return fmt.Errorf("dump sarif: %w", err)
}
return nil
}
// Validate validates a SARIF log against the bundled SARIF 2.1.0 schema.
func Validate(log *Log) error {
schema, err := Schema()
if err != nil {
return err
}
data, err := json.Marshal(log)
if err != nil {
return fmt.Errorf("validate sarif: %w", err)
}
value, err := jsonschema.UnmarshalJSON(bytes.NewReader(data))
if err != nil {
return fmt.Errorf("validate sarif: %w", err)
}
if err := schema.Validate(value); err != nil {
return fmt.Errorf("validate sarif: %w", err)
}
return nil
}
// Valid reports whether log validates against the bundled SARIF 2.1.0 schema.
func Valid(log *Log) bool {
return Validate(log) == nil
}
func includeNonZero(value any) bool {
return !reflect.ValueOf(value).IsZero()
}
func includeNonDefault(value any, defaultValue any) bool {
valueRef := reflect.ValueOf(value)
defaultRef := reflect.ValueOf(defaultValue)
if !valueRef.IsValid() {
return false
}
if defaultRef.IsValid() && defaultRef.Kind() == reflect.Slice {
if valueRef.Kind() != reflect.Slice || valueRef.IsNil() {
return false
}
if defaultRef.Len() == 0 {
return valueRef.Len() > 0
}
return !reflect.DeepEqual(value, defaultValue)
}
if defaultRef.IsValid() && defaultRef.Kind() == reflect.String && valueRef.IsZero() {
return false
}
return !reflect.DeepEqual(value, defaultValue)
}
// Schema returns the compiled bundled SARIF 2.1.0 JSON schema.
func Schema() (*jsonschema.Schema, error) {
compiledSchemaOnce.Do(func() {
data, err := schemaFS.ReadFile(schemaPath)
if err != nil {
compiledSchemaErr = fmt.Errorf("compile sarif schema: %w", err)
return
}
compiler := jsonschema.NewCompiler()
compiler.DefaultDraft(jsonschema.Draft7)
doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(data))
if err != nil {
compiledSchemaErr = fmt.Errorf("compile sarif schema: %w", err)
return
}
if err := compiler.AddResource(schemaPath, doc); err != nil {
compiledSchemaErr = fmt.Errorf("compile sarif schema: %w", err)
return
}
compiledSchema, compiledSchemaErr = compiler.Compile(schemaPath)
if compiledSchemaErr != nil {
compiledSchemaErr = fmt.Errorf("compile sarif schema: %w", compiledSchemaErr)
}
})
return compiledSchema, compiledSchemaErr
}