mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(cli): upgrade secret scanner
This commit is contained in:
26
cli/detect/report/constants.go
Normal file
26
cli/detect/report/constants.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
const version = "v8.0.0"
|
||||
const driver = "gitleaks"
|
||||
100
cli/detect/report/csv.go
Normal file
100
cli/detect/report/csv.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CsvReporter struct {
|
||||
}
|
||||
|
||||
var _ Reporter = (*CsvReporter)(nil)
|
||||
|
||||
func (r *CsvReporter) Write(w io.WriteCloser, findings []Finding) error {
|
||||
if len(findings) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
cw = csv.NewWriter(w)
|
||||
err error
|
||||
)
|
||||
columns := []string{"RuleID",
|
||||
"Commit",
|
||||
"File",
|
||||
"SymlinkFile",
|
||||
"Secret",
|
||||
"Match",
|
||||
"StartLine",
|
||||
"EndLine",
|
||||
"StartColumn",
|
||||
"EndColumn",
|
||||
"Author",
|
||||
"Message",
|
||||
"Date",
|
||||
"Email",
|
||||
"Fingerprint",
|
||||
"Tags",
|
||||
}
|
||||
// A miserable attempt at "omitempty" so tests don't yell at me.
|
||||
if findings[0].Link != "" {
|
||||
columns = append(columns, "Link")
|
||||
}
|
||||
|
||||
if err = cw.Write(columns); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, f := range findings {
|
||||
row := []string{f.RuleID,
|
||||
f.Commit,
|
||||
f.File,
|
||||
f.SymlinkFile,
|
||||
f.Secret,
|
||||
f.Match,
|
||||
strconv.Itoa(f.StartLine),
|
||||
strconv.Itoa(f.EndLine),
|
||||
strconv.Itoa(f.StartColumn),
|
||||
strconv.Itoa(f.EndColumn),
|
||||
f.Author,
|
||||
f.Message,
|
||||
f.Date,
|
||||
f.Email,
|
||||
f.Fingerprint,
|
||||
strings.Join(f.Tags, " "),
|
||||
}
|
||||
if findings[0].Link != "" {
|
||||
row = append(row, f.Link)
|
||||
}
|
||||
|
||||
if err = cw.Write(row); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cw.Flush()
|
||||
return cw.Error()
|
||||
}
|
||||
92
cli/detect/report/finding.go
Normal file
92
cli/detect/report/finding.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Finding contains information about strings that
|
||||
// have been captured by a tree-sitter query.
|
||||
type Finding struct {
|
||||
// Rule is the name of the rule that was matched
|
||||
RuleID string
|
||||
Description string
|
||||
|
||||
StartLine int
|
||||
EndLine int
|
||||
StartColumn int
|
||||
EndColumn int
|
||||
|
||||
Line string `json:"-"`
|
||||
|
||||
Match string
|
||||
|
||||
// Secret contains the full content of what is matched in
|
||||
// the tree-sitter query.
|
||||
Secret string
|
||||
|
||||
// File is the name of the file containing the finding
|
||||
File string
|
||||
SymlinkFile string
|
||||
Commit string
|
||||
Link string `json:",omitempty"`
|
||||
|
||||
// Entropy is the shannon entropy of Value
|
||||
Entropy float32
|
||||
|
||||
Author string
|
||||
Email string
|
||||
Date string
|
||||
Message string
|
||||
Tags []string
|
||||
|
||||
// unique identifier
|
||||
Fingerprint string
|
||||
}
|
||||
|
||||
// Redact removes sensitive information from a finding.
|
||||
func (f *Finding) Redact(percent uint) {
|
||||
secret := maskSecret(f.Secret, percent)
|
||||
if percent >= 100 {
|
||||
secret = "REDACTED"
|
||||
}
|
||||
f.Line = strings.Replace(f.Line, f.Secret, secret, -1)
|
||||
f.Match = strings.Replace(f.Match, f.Secret, secret, -1)
|
||||
f.Secret = secret
|
||||
}
|
||||
|
||||
func maskSecret(secret string, percent uint) string {
|
||||
if percent > 100 {
|
||||
percent = 100
|
||||
}
|
||||
len := float64(len(secret))
|
||||
if len <= 0 {
|
||||
return secret
|
||||
}
|
||||
prc := float64(100 - percent)
|
||||
lth := int64(math.RoundToEven(len * prc / float64(100)))
|
||||
|
||||
return secret[:lth] + "..."
|
||||
}
|
||||
39
cli/detect/report/json.go
Normal file
39
cli/detect/report/json.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
type JsonReporter struct {
|
||||
}
|
||||
|
||||
var _ Reporter = (*JsonReporter)(nil)
|
||||
|
||||
func (t *JsonReporter) Write(w io.WriteCloser, findings []Finding) error {
|
||||
encoder := json.NewEncoder(w)
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(findings)
|
||||
}
|
||||
129
cli/detect/report/junit.go
Normal file
129
cli/detect/report/junit.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type JunitReporter struct {
|
||||
}
|
||||
|
||||
var _ Reporter = (*JunitReporter)(nil)
|
||||
|
||||
func (r *JunitReporter) Write(w io.WriteCloser, findings []Finding) error {
|
||||
testSuites := TestSuites{
|
||||
TestSuites: getTestSuites(findings),
|
||||
}
|
||||
|
||||
io.WriteString(w, xml.Header)
|
||||
encoder := xml.NewEncoder(w)
|
||||
encoder.Indent("", "\t")
|
||||
return encoder.Encode(testSuites)
|
||||
}
|
||||
|
||||
func getTestSuites(findings []Finding) []TestSuite {
|
||||
return []TestSuite{
|
||||
{
|
||||
Failures: strconv.Itoa(len(findings)),
|
||||
Name: "gitleaks",
|
||||
Tests: strconv.Itoa(len(findings)),
|
||||
TestCases: getTestCases(findings),
|
||||
Time: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTestCases(findings []Finding) []TestCase {
|
||||
testCases := []TestCase{}
|
||||
for _, f := range findings {
|
||||
testCase := TestCase{
|
||||
Classname: f.Description,
|
||||
Failure: getFailure(f),
|
||||
File: f.File,
|
||||
Name: getMessage(f),
|
||||
Time: "",
|
||||
}
|
||||
testCases = append(testCases, testCase)
|
||||
}
|
||||
return testCases
|
||||
}
|
||||
|
||||
func getFailure(f Finding) Failure {
|
||||
return Failure{
|
||||
Data: getData(f),
|
||||
Message: getMessage(f),
|
||||
Type: f.Description,
|
||||
}
|
||||
}
|
||||
|
||||
func getData(f Finding) string {
|
||||
data, err := json.MarshalIndent(f, "", "\t")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func getMessage(f Finding) string {
|
||||
if f.Commit == "" {
|
||||
return fmt.Sprintf("%s has detected a secret in file %s, line %s.", f.RuleID, f.File, strconv.Itoa(f.StartLine))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s has detected a secret in file %s, line %s, at commit %s.", f.RuleID, f.File, strconv.Itoa(f.StartLine), f.Commit)
|
||||
}
|
||||
|
||||
type TestSuites struct {
|
||||
XMLName xml.Name `xml:"testsuites"`
|
||||
TestSuites []TestSuite
|
||||
}
|
||||
|
||||
type TestSuite struct {
|
||||
XMLName xml.Name `xml:"testsuite"`
|
||||
Failures string `xml:"failures,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
Tests string `xml:"tests,attr"`
|
||||
TestCases []TestCase `xml:"testcase"`
|
||||
Time string `xml:"time,attr"`
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
XMLName xml.Name `xml:"testcase"`
|
||||
Classname string `xml:"classname,attr"`
|
||||
Failure Failure `xml:"failure"`
|
||||
File string `xml:"file,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
}
|
||||
|
||||
type Failure struct {
|
||||
XMLName xml.Name `xml:"failure"`
|
||||
Data string `xml:",chardata"`
|
||||
Message string `xml:"message,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
}
|
||||
38
cli/detect/report/report.go
Normal file
38
cli/detect/report/report.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
// https://cwe.mitre.org/data/definitions/798.html
|
||||
CWE = "CWE-798"
|
||||
CWE_DESCRIPTION = "Use of Hard-coded Credentials"
|
||||
StdoutReportPath = "-"
|
||||
)
|
||||
|
||||
type Reporter interface {
|
||||
Write(w io.WriteCloser, findings []Finding) error
|
||||
}
|
||||
239
cli/detect/report/sarif.go
Normal file
239
cli/detect/report/sarif.go
Normal file
@@ -0,0 +1,239 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/Infisical/infisical-merge/detect/config"
|
||||
)
|
||||
|
||||
type SarifReporter struct {
|
||||
OrderedRules []config.Rule
|
||||
}
|
||||
|
||||
var _ Reporter = (*SarifReporter)(nil)
|
||||
|
||||
func (r *SarifReporter) Write(w io.WriteCloser, findings []Finding) error {
|
||||
sarif := Sarif{
|
||||
Schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
||||
Version: "2.1.0",
|
||||
Runs: r.getRuns(findings),
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(w)
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(sarif)
|
||||
}
|
||||
|
||||
func (r *SarifReporter) getRuns(findings []Finding) []Runs {
|
||||
return []Runs{
|
||||
{
|
||||
Tool: r.getTool(),
|
||||
Results: getResults(findings),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SarifReporter) getTool() Tool {
|
||||
tool := Tool{
|
||||
Driver: Driver{
|
||||
Name: driver,
|
||||
SemanticVersion: version,
|
||||
InformationUri: "https://github.com/gitleaks/gitleaks",
|
||||
Rules: r.getRules(),
|
||||
},
|
||||
}
|
||||
|
||||
// if this tool has no rules, ensure that it is represented as [] instead of null/nil
|
||||
if hasEmptyRules(tool) {
|
||||
tool.Driver.Rules = make([]Rules, 0)
|
||||
}
|
||||
|
||||
return tool
|
||||
}
|
||||
|
||||
func hasEmptyRules(tool Tool) bool {
|
||||
return len(tool.Driver.Rules) == 0
|
||||
}
|
||||
|
||||
func (r *SarifReporter) getRules() []Rules {
|
||||
// TODO for _, rule := range cfg.Rules {
|
||||
var rules []Rules
|
||||
for _, rule := range r.OrderedRules {
|
||||
rules = append(rules, Rules{
|
||||
ID: rule.RuleID,
|
||||
Description: ShortDescription{
|
||||
Text: rule.Description,
|
||||
},
|
||||
})
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
func messageText(f Finding) string {
|
||||
if f.Commit == "" {
|
||||
return fmt.Sprintf("%s has detected secret for file %s.", f.RuleID, f.File)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s has detected secret for file %s at commit %s.", f.RuleID, f.File, f.Commit)
|
||||
|
||||
}
|
||||
|
||||
func getResults(findings []Finding) []Results {
|
||||
results := []Results{}
|
||||
for _, f := range findings {
|
||||
r := Results{
|
||||
Message: Message{
|
||||
Text: messageText(f),
|
||||
},
|
||||
RuleId: f.RuleID,
|
||||
Locations: getLocation(f),
|
||||
// This information goes in partial fingerprings until revision
|
||||
// data can be added somewhere else
|
||||
PartialFingerPrints: PartialFingerPrints{
|
||||
CommitSha: f.Commit,
|
||||
Email: f.Email,
|
||||
CommitMessage: f.Message,
|
||||
Date: f.Date,
|
||||
Author: f.Author,
|
||||
},
|
||||
Properties: Properties{
|
||||
Tags: f.Tags,
|
||||
},
|
||||
}
|
||||
results = append(results, r)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func getLocation(f Finding) []Locations {
|
||||
uri := f.File
|
||||
if f.SymlinkFile != "" {
|
||||
uri = f.SymlinkFile
|
||||
}
|
||||
return []Locations{
|
||||
{
|
||||
PhysicalLocation: PhysicalLocation{
|
||||
ArtifactLocation: ArtifactLocation{
|
||||
URI: uri,
|
||||
},
|
||||
Region: Region{
|
||||
StartLine: f.StartLine,
|
||||
EndLine: f.EndLine,
|
||||
StartColumn: f.StartColumn,
|
||||
EndColumn: f.EndColumn,
|
||||
Snippet: Snippet{
|
||||
Text: f.Secret,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type PartialFingerPrints struct {
|
||||
CommitSha string `json:"commitSha"`
|
||||
Email string `json:"email"`
|
||||
Author string `json:"author"`
|
||||
Date string `json:"date"`
|
||||
CommitMessage string `json:"commitMessage"`
|
||||
}
|
||||
|
||||
type Sarif struct {
|
||||
Schema string `json:"$schema"`
|
||||
Version string `json:"version"`
|
||||
Runs []Runs `json:"runs"`
|
||||
}
|
||||
|
||||
type ShortDescription struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type FullDescription struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type Rules struct {
|
||||
ID string `json:"id"`
|
||||
Description ShortDescription `json:"shortDescription"`
|
||||
}
|
||||
|
||||
type Driver struct {
|
||||
Name string `json:"name"`
|
||||
SemanticVersion string `json:"semanticVersion"`
|
||||
InformationUri string `json:"informationUri"`
|
||||
Rules []Rules `json:"rules"`
|
||||
}
|
||||
|
||||
type Tool struct {
|
||||
Driver Driver `json:"driver"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type ArtifactLocation struct {
|
||||
URI string `json:"uri"`
|
||||
}
|
||||
|
||||
type Region struct {
|
||||
StartLine int `json:"startLine"`
|
||||
StartColumn int `json:"startColumn"`
|
||||
EndLine int `json:"endLine"`
|
||||
EndColumn int `json:"endColumn"`
|
||||
Snippet Snippet `json:"snippet"`
|
||||
}
|
||||
|
||||
type Snippet struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type PhysicalLocation struct {
|
||||
ArtifactLocation ArtifactLocation `json:"artifactLocation"`
|
||||
Region Region `json:"region"`
|
||||
}
|
||||
|
||||
type Locations struct {
|
||||
PhysicalLocation PhysicalLocation `json:"physicalLocation"`
|
||||
}
|
||||
|
||||
type Properties struct {
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type Results struct {
|
||||
Message Message `json:"message"`
|
||||
RuleId string `json:"ruleId"`
|
||||
Locations []Locations `json:"locations"`
|
||||
PartialFingerPrints `json:"partialFingerprints"`
|
||||
Properties Properties `json:"properties"`
|
||||
}
|
||||
|
||||
type Runs struct {
|
||||
Tool Tool `json:"tool"`
|
||||
Results []Results `json:"results"`
|
||||
}
|
||||
68
cli/detect/report/template.go
Normal file
68
cli/detect/report/template.go
Normal file
@@ -0,0 +1,68 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
)
|
||||
|
||||
type TemplateReporter struct {
|
||||
template *template.Template
|
||||
}
|
||||
|
||||
var _ Reporter = (*TemplateReporter)(nil)
|
||||
|
||||
func NewTemplateReporter(templatePath string) (*TemplateReporter, error) {
|
||||
if templatePath == "" {
|
||||
return nil, fmt.Errorf("template path cannot be empty")
|
||||
}
|
||||
|
||||
file, err := os.ReadFile(templatePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading file: %w", err)
|
||||
}
|
||||
templateText := string(file)
|
||||
|
||||
// TODO: Add helper functions like escaping for JSON, XML, etc.
|
||||
t := template.New("custom")
|
||||
t = t.Funcs(sprig.TxtFuncMap())
|
||||
t, err = t.Parse(templateText)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing file: %w", err)
|
||||
}
|
||||
return &TemplateReporter{template: t}, nil
|
||||
}
|
||||
|
||||
// writeTemplate renders the findings using the user-provided template.
|
||||
// https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-go
|
||||
func (t *TemplateReporter) Write(w io.WriteCloser, findings []Finding) error {
|
||||
if err := t.template.Execute(w, findings); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user