Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Library and example implementation that extracts code context for any issue #54

Merged
merged 21 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ec24640
add a small library that allows for adding code context to issues
northdpole Dec 28, 2023
7f40c74
Update pkg/context/context_test.go
northdpole Dec 28, 2023
0800c63
Update pkg/context/context_test.go
northdpole Dec 28, 2023
bcc8957
Update pkg/context/context_test.go
northdpole Dec 28, 2023
e641f41
Update pkg/context/context_test.go
northdpole Dec 28, 2023
fd3dd2d
Update pkg/context/context_test.go
northdpole Dec 28, 2023
8ad121f
Update pkg/context/context_test.go
northdpole Dec 28, 2023
80e1d6e
migrate producers to add context segments
northdpole Dec 28, 2023
87fb704
Update components/producers/golang-gosec/main_test.go
northdpole Dec 29, 2023
64c969e
Update components/producers/kics/main_test.go
northdpole Dec 29, 2023
4932157
Update components/producers/python-bandit/main_test.go
northdpole Dec 29, 2023
da98e58
Update components/producers/python-bandit/main_test.go
northdpole Dec 29, 2023
5d08f28
Update components/producers/semgrep/main_test.go
northdpole Dec 29, 2023
df25386
tfsec
northdpole Dec 28, 2023
c8a525c
trufflehog
northdpole Dec 30, 2023
d943a3c
eslint
northdpole Dec 30, 2023
1925c94
lint
northdpole Dec 30, 2023
5277194
Update components/producers/terraform-tfsec/main_test.go
northdpole Jan 2, 2024
3c80b7d
Update components/producers/trufflehog/main_test.go
northdpole Jan 2, 2024
a102192
Update components/producers/typescript-eslint/main_test.go
northdpole Jan 2, 2024
09d68e7
Update components/producers/typescript-eslint/types/eslint-issue.go
northdpole Jan 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 65 additions & 52 deletions api/proto/v1/issue.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions api/proto/v1/issue.proto
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ message Issue {
string uuid = 10;
// optional field that allows us to also encode a bill of materials in an issue
optional string cyclone_d_x_s_b_o_m = 11;

// optional string that allows producers to communicate relevant code/request segments
optional string context_segment = 12;
}

/* Represents an issue that has been enriched with metadata from the enrichment service */
Expand Down
3 changes: 3 additions & 0 deletions components/producers/golang-gosec/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ go_binary(
deps = [
"//api/proto/v1",
"//components/producers",
"//pkg/context",
],
)

Expand All @@ -24,6 +25,8 @@ go_test(
deps = [
"//api/proto/v1",
"//components/producers",
"//pkg/context",
"//pkg/testutil",
"//third_party/go/github.com/stretchr/testify",
],
)
Expand Down
21 changes: 15 additions & 6 deletions components/producers/golang-gosec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"

v1 "github.com/ocurity/dracon/api/proto/v1"
"github.com/ocurity/dracon/pkg/context"

"github.com/ocurity/dracon/components/producers"
)
Expand All @@ -24,8 +25,10 @@ func main() {
log.Fatal(err)
}

issues := parseIssues(&results)

issues, err := parseIssues(&results)
if err != nil {
log.Fatal(err)
}
if err := producers.WriteDraconOut(
"gosec",
issues,
Expand All @@ -34,20 +37,26 @@ func main() {
}
}

func parseIssues(out *GoSecOut) []*v1.Issue {
func parseIssues(out *GoSecOut) ([]*v1.Issue, error) {
issues := []*v1.Issue{}
for _, r := range out.Issues {
issues = append(issues, &v1.Issue{
iss := &v1.Issue{
Target: fmt.Sprintf("%s:%v", r.File, r.Line),
Type: r.RuleID,
Title: r.Details,
Severity: v1.Severity(v1.Severity_value[fmt.Sprintf("SEVERITY_%s", r.Severity)]),
Cvss: 0.0,
Confidence: v1.Confidence(v1.Confidence_value[fmt.Sprintf("CONFIDENCE_%s", r.Confidence)]),
Description: r.Code,
})
}
code, err := context.ExtractCode(iss)
if err != nil {
return nil, err
}
iss.ContextSegment = &code
issues = append(issues, iss)
}
return issues
return issues, nil
}

// GoSecOut represents the output of a GoSec run.
Expand Down
50 changes: 37 additions & 13 deletions components/producers/golang-gosec/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,40 @@ package main

import (
"encoding/json"
"fmt"
"os"
"testing"

v1 "github.com/ocurity/dracon/api/proto/v1"
"github.com/ocurity/dracon/pkg/testutil"

"github.com/stretchr/testify/assert"
)

const exampleOutput = `
var code = `func GetProducts(ctx context.Context, db *sql.DB, category string) ([]Product, error) {
rows, err := db.QueryContext(ctx, "SELECT * FROM product WHERE category='"+category+"'")
if err != nil {
return nil, err
}
defer rows.Close()
var products []Product
for rows.Next() {
var product Product
if err := rows.Scan(&product.Id, &product.Name, &product.Category, &product.Price); err != nil {
return nil, err
}`

var gosecout = `
{
"Issues": [
{
"severity": "MEDIUM",
"confidence": "HIGH",
"rule_id": "G304",
"details": "Potential file inclusion via variable",
"file": "/tmp/source/foo.go",
"file": "%s",
"code": "ioutil.ReadFile(path)",
"line": "33",
"line": "2",
"column": "44"
}
],
Expand All @@ -32,20 +48,28 @@ const exampleOutput = `
}`

func TestParseIssues(t *testing.T) {

northdpole marked this conversation as resolved.
Show resolved Hide resolved
f, err := testutil.CreateFile("gosec_tests_vuln_code", code)
if err != nil {
t.Error(err)
}
defer os.Remove(f.Name())
exampleOutput := fmt.Sprintf(gosecout, f.Name())
var results GoSecOut
err := json.Unmarshal([]byte(exampleOutput), &results)
err = json.Unmarshal([]byte(exampleOutput), &results)
assert.Nil(t, err)

issues := parseIssues(&results)

issues, err := parseIssues(&results)
assert.Nil(t, err)
expectedIssue := &v1.Issue{
Target: "/tmp/source/foo.go:33",
Type: "G304",
Title: "Potential file inclusion via variable",
Severity: v1.Severity_SEVERITY_MEDIUM,
Cvss: 0.0,
Confidence: v1.Confidence_CONFIDENCE_HIGH,
Description: "ioutil.ReadFile(path)",
Target: fmt.Sprintf("%s:2", f.Name()),
Type: "G304",
Title: "Potential file inclusion via variable",
Severity: v1.Severity_SEVERITY_MEDIUM,
Cvss: 0.0,
Confidence: v1.Confidence_CONFIDENCE_HIGH,
Description: "ioutil.ReadFile(path)",
ContextSegment: &code,
}

assert.Equal(t, []*v1.Issue{expectedIssue}, issues)
Expand Down
3 changes: 3 additions & 0 deletions components/producers/kics/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ go_binary(
"//api/proto/v1",
"//components/producers",
"//components/producers/kics/types",
"//pkg/context",
"//pkg/sarif",
],
)
Expand All @@ -30,6 +31,8 @@ go_test(
"//components/producers/kics/types",
"//pkg/sarif",
"//third_party/go/github.com/stretchr/testify",
"//pkg/testutil",
"//pkg/context",
],
)

Expand Down
22 changes: 16 additions & 6 deletions components/producers/kics/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
v1 "github.com/ocurity/dracon/api/proto/v1"
"github.com/ocurity/dracon/components/producers"
"github.com/ocurity/dracon/components/producers/kics/types"
"github.com/ocurity/dracon/pkg/context"
"github.com/ocurity/dracon/pkg/sarif"
)

Expand Down Expand Up @@ -48,14 +49,18 @@ func main() {
if err := producers.ParseJSON(inFile, &results); err != nil {
log.Fatal(err)
}
if err := producers.WriteDraconOut("KICS", parseOut(results)); err != nil {
res, err := parseOut(results)
if err != nil {
log.Fatal(err)
}
if err := producers.WriteDraconOut("KICS", res); err != nil {
log.Fatal(err)
}

}
}

func parseOut(results types.KICSOut) []*v1.Issue {
func parseOut(results types.KICSOut) ([]*v1.Issue, error) {
issues := []*v1.Issue{}
for _, query := range results.Queries {
queryCopy := query
Expand All @@ -64,8 +69,7 @@ func parseOut(results types.KICSOut) []*v1.Issue {
for _, file := range query.Files {
queryCopy.Files = []types.KICSFile{file}
description, _ := json.Marshal(queryCopy)

issues = append(issues, &v1.Issue{
iss := &v1.Issue{
Target: fmt.Sprintf("%s:%d", file.FileName, file.Line),
Type: file.IssueType,
Severity: KICSSeverityToDracon(query.Severity),
Expand All @@ -75,11 +79,17 @@ func parseOut(results types.KICSOut) []*v1.Issue {
file.ResourceType,
file.ResourceName),
Description: string(description),
})
}
cs, err := context.ExtractCode(iss)
if err != nil {
return nil, err
}
iss.ContextSegment = &cs
issues = append(issues, iss)

}
}
return issues
return issues, nil
}

// KICSSeverityToDracon maps KCIS Severity Strings to dracon struct.
Expand Down
Loading
Loading