Skip to content

Commit 6466fb9

Browse files
Sarif genesis (#1)
* genesis * fix typo * fix newline & go version
1 parent abcbe78 commit 6466fb9

18 files changed

+1112
-0
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# sarif
2+
3+
sarif is golang implementation of Static Analysis Results Interchange Format (SARIF) . SARIF is a standard data model and serialization format for static analysis results.
4+
5+
To view any SARIF file visit [sarif-web-component](https://microsoft.github.io/sarif-web-component/)
6+
7+
# References
8+
9+
[sarif-specification](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)
10+
11+
[sarif-tutorials](https://github.com/microsoft/sarif-tutorials)

example/main.go

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
7+
"github.com/projectdiscovery/sarif"
8+
)
9+
10+
func main() {
11+
// create new sarif report
12+
report := sarif.NewReport()
13+
// Extra metadata can be added to any type of sarif
14+
extrametadata := map[string]string{
15+
"payload": "'sleep(10)--",
16+
"Severity Rating": "10",
17+
}
18+
19+
// to create new tool/template/plugin
20+
rule1 := sarif.ReportingDescriptor{
21+
Id: "template1",
22+
Name: "SQL Injection CVE-2022-xx",
23+
ShortDescription: &sarif.MultiformatMessageString{
24+
Text: "SQL Injection Vulnerability due to Dependency",
25+
},
26+
FullDescription: &sarif.MultiformatMessageString{
27+
Text: "Full Description of Vulnerability with references",
28+
},
29+
Properties: extrametadata,
30+
}
31+
32+
// register details of the static analysis tool
33+
report.RegisterTool(sarif.ToolComponent{
34+
Name: "vulnscanner",
35+
Organization: "ProjectDiscovery",
36+
Product: "Scanners",
37+
ShortDescription: &sarif.MultiformatMessageString{
38+
Text: "Vulnerability Scanner",
39+
},
40+
FullDescription: &sarif.MultiformatMessageString{
41+
Text: "Template Based Vulnerability Scanner",
42+
},
43+
FullName: "vulnscanner v2.1.1",
44+
SemanticVersion: "v2.1.1",
45+
DownloadURI: "https://github.com/projectdiscovery/xxx",
46+
Rules: []sarif.ReportingDescriptor{rule1},
47+
// The order of rules/templates/plugins is important here
48+
// this index is referenced when a result/vulnerability is found
49+
})
50+
51+
// Output of static analysis tool
52+
outfiles := sarif.ArtifactLocation{
53+
Uri: "file:///var/log/xxx.log",
54+
Description: &sarif.Message{
55+
Text: "Generated using vulnscanner",
56+
},
57+
}
58+
59+
// to register tool invocation and env
60+
report.RegisterToolInvocation(sarif.Invocation{
61+
CommandLine: "vulnscanner",
62+
Arguments: []string{"-sC", "-sV"},
63+
ResponseFiles: []sarif.ArtifactLocation{outfiles},
64+
ExecutionSuccessful: true,
65+
WorkingDirectory: sarif.ArtifactLocation{
66+
Uri: "file:///opt",
67+
},
68+
EnvironmentVariables: map[string]string{
69+
"GOPROXY": "direct",
70+
},
71+
})
72+
73+
// locations of a particular target can be linked to result
74+
// using sarif.Location
75+
location := sarif.Location{
76+
Message: &sarif.Message{
77+
Text: "status.projectdiscovery.io",
78+
},
79+
PhysicalLocation: sarif.PhysicalLocation{
80+
Address: sarif.Address{
81+
Name: "Address of Location",
82+
FullyQualifiedName: "Name of Address",
83+
Kind: "parameter",
84+
},
85+
ArtifactLocation: sarif.ArtifactLocation{
86+
Uri: "https://projectdiscovery.com/api/user=admin'",
87+
Description: &sarif.Message{
88+
Text: "https://projectdiscovery.com/api/user=admin'",
89+
},
90+
},
91+
},
92+
}
93+
94+
// Register results with severity etc
95+
report.RegisterResult(sarif.Result{
96+
RuleId: "template1",
97+
RuleIndex: 0,
98+
Level: sarif.Error,
99+
Kind: sarif.Open,
100+
AnalysisTarget: sarif.ArtifactLocation{
101+
Uri: "https://projectdiscovery.io",
102+
},
103+
Message: &sarif.Message{
104+
Text: "SQL Injection",
105+
},
106+
Rule: sarif.ReportingDescriptorReference{
107+
Id: "template1",
108+
ToolComponent: sarif.ToolComponent{
109+
Name: "SQL Injection in xxx",
110+
ShortDescription: rule1.MessageStrings,
111+
},
112+
},
113+
Locations: []sarif.Location{location},
114+
})
115+
116+
bin, err := report.Export()
117+
if err != nil {
118+
log.Fatalf("failed to export report")
119+
}
120+
121+
if err = os.WriteFile("sql_report.sarif", bin, 0644); err != nil {
122+
log.Fatalf("failed to write file generated.sarif %v", err)
123+
}
124+
125+
log.Printf("Report sql_report.sarif created")
126+
}

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/projectdiscovery/sarif
2+
3+
go 1.18

sarif.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package sarif
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
)
7+
8+
// Report encapsulates SarifLog Object and generates .sarif Report
9+
type Report struct {
10+
Sarif *SarifLog // SarifLog Object
11+
run Run // Describes a single run of an analysis tool
12+
}
13+
14+
// RegisterTool registers tool details
15+
func (r *Report) RegisterTool(driver ToolComponent) {
16+
r.run.Tool.Driver = driver
17+
}
18+
19+
// RegisterToolExtension registers tool plugins/extensions/templates
20+
func (r *Report) RegisterToolExtension(extensions []ToolComponent) {
21+
r.run.Tool.Extensions = extensions
22+
}
23+
24+
// RegisterToolInvocation registers runtime enviornment when tool was run
25+
func (r *Report) RegisterToolInvocation(invocation Invocation) {
26+
r.run.Invocations = append(r.run.Invocations, invocation)
27+
}
28+
29+
// RegisterResult registers result
30+
func (r *Report) RegisterResult(result Result) {
31+
r.run.Result = append(r.run.Result, result)
32+
}
33+
34+
// Export
35+
func (r *Report) Export() ([]byte, error) {
36+
r.Sarif.Runs = append(r.Sarif.Runs, r.run)
37+
bin, err := json.MarshalIndent(r.Sarif, "", "\t")
38+
return bin, err
39+
}
40+
41+
// NewReport Creates New Report Instance
42+
func NewReport() *Report {
43+
sf := SarifLog{
44+
Version: "2.1.0",
45+
Schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
46+
Runs: []Run{},
47+
}
48+
49+
sarifExporter := Report{
50+
Sarif: &sf,
51+
}
52+
run := Run{
53+
Invocations: []Invocation{},
54+
Result: []Result{},
55+
}
56+
sarifExporter.run = run
57+
58+
return &sarifExporter
59+
}
60+
61+
func OpenReport(filename string) (*Report, error) {
62+
var sarifObject SarifLog
63+
64+
bin, err := os.ReadFile(filename)
65+
if err != nil {
66+
return nil, err
67+
}
68+
if err = json.Unmarshal(bin, &sarifObject); err != nil {
69+
return nil, err
70+
}
71+
report := Report{
72+
Sarif: &sarifObject,
73+
}
74+
return &report, nil
75+
}

sarif_test.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package sarif_test
2+
3+
import (
4+
"io/fs"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
9+
"github.com/projectdiscovery/sarif"
10+
)
11+
12+
func Test_UnmarshalReport(t *testing.T) {
13+
sarifFiles := []string{}
14+
15+
if err := filepath.WalkDir("static", func(path string, d fs.DirEntry, err error) error {
16+
if !d.IsDir() {
17+
if strings.HasSuffix(d.Name(), ".sarif") || strings.HasSuffix(d.Name(), ".sarif.json") {
18+
sarifFiles = append(sarifFiles, path)
19+
}
20+
}
21+
return nil
22+
}); err != nil {
23+
t.Fatal(err)
24+
}
25+
26+
for _, v := range sarifFiles {
27+
_, er := sarif.OpenReport(v)
28+
if er != nil {
29+
t.Logf("failed to read %v sarif report", v)
30+
t.Error(er)
31+
} else {
32+
t.Logf("Unmarshall test successful: %v\n", v)
33+
}
34+
}
35+
}
36+
37+
func Test_Report(t *testing.T) {
38+
report := sarif.NewReport()
39+
40+
metadata := map[string]string{
41+
"payload": "'sleep(10)--",
42+
"Severity Rating": "10",
43+
}
44+
45+
// rule or template
46+
rule1 := sarif.ReportingDescriptor{
47+
Id: "template1",
48+
Name: "SQL Injection CVE-2022-xx",
49+
ShortDescription: &sarif.MultiformatMessageString{
50+
Text: "SQL Injection Vulnerability due to Dependency",
51+
},
52+
FullDescription: &sarif.MultiformatMessageString{
53+
Text: "Full Description of Vulnerability with references",
54+
},
55+
Properties: metadata,
56+
}
57+
58+
report.RegisterTool(sarif.ToolComponent{
59+
Name: "vulnscanner",
60+
Organization: "ProjectDiscovery",
61+
Product: "Scanners",
62+
ShortDescription: &sarif.MultiformatMessageString{
63+
Text: "Vulnerability Scanner",
64+
},
65+
FullDescription: &sarif.MultiformatMessageString{
66+
Text: "Template Based Vulnerability Scanner",
67+
},
68+
FullName: "vulnscanner v2.1.1",
69+
SemanticVersion: "v2.1.1",
70+
DownloadURI: "https://github.com/projectdiscovery/xxx",
71+
Rules: []sarif.ReportingDescriptor{rule1},
72+
})
73+
74+
outfiles := sarif.ArtifactLocation{
75+
Uri: "file:///etc/passwd",
76+
Description: &sarif.Message{
77+
Text: "Generated using vulnscanner",
78+
},
79+
}
80+
81+
report.RegisterToolInvocation(sarif.Invocation{
82+
CommandLine: "vulnscanner",
83+
Arguments: []string{"-sC", "-sV"},
84+
ResponseFiles: []sarif.ArtifactLocation{outfiles},
85+
ExecutionSuccessful: true,
86+
WorkingDirectory: sarif.ArtifactLocation{
87+
Uri: "file:///opt",
88+
},
89+
EnvironmentVariables: map[string]string{
90+
"GOPROXY": "direct",
91+
},
92+
})
93+
94+
loc := sarif.Location{
95+
Message: &sarif.Message{
96+
Text: "status.projectdiscovery.io",
97+
},
98+
PhysicalLocation: sarif.PhysicalLocation{
99+
Address: sarif.Address{
100+
Name: "Address of Location",
101+
FullyQualifiedName: "Name of Address",
102+
Kind: "parameter",
103+
},
104+
ArtifactLocation: sarif.ArtifactLocation{
105+
Uri: "https://projectdiscovery.com/api/user=admin'",
106+
Description: &sarif.Message{
107+
Text: "https://projectdiscovery.com/api/user=admin'",
108+
},
109+
},
110+
},
111+
}
112+
113+
report.RegisterResult(sarif.Result{
114+
RuleId: "template1",
115+
RuleIndex: 0,
116+
Level: sarif.Error,
117+
Kind: sarif.Review,
118+
AnalysisTarget: sarif.ArtifactLocation{
119+
Uri: "https://projectdiscovery.io",
120+
},
121+
Message: &sarif.Message{
122+
Text: "SQL Injection",
123+
},
124+
Rule: sarif.ReportingDescriptorReference{
125+
Id: "template1",
126+
ToolComponent: sarif.ToolComponent{
127+
Name: "SQL Injection in xxx",
128+
ShortDescription: rule1.MessageStrings,
129+
},
130+
},
131+
Locations: []sarif.Location{loc},
132+
})
133+
134+
if _, err := report.Export(); err != nil {
135+
t.Fatalf("failed to export report")
136+
}
137+
138+
}

0 commit comments

Comments
 (0)