1package output 2 3import ( 4 "fmt" 5 "github.com/securego/gosec/v2" 6 "strconv" 7 "strings" 8) 9 10type sarifLevel string 11 12const ( 13 sarifNone = sarifLevel("none") 14 sarifNote = sarifLevel("note") 15 sarifWarning = sarifLevel("warning") 16 sarifError = sarifLevel("error") 17) 18 19type sarifProperties struct { 20 Tags []string `json:"tags"` 21} 22 23type sarifRule struct { 24 ID string `json:"id"` 25 Name string `json:"name"` 26 ShortDescription *sarifMessage `json:"shortDescription"` 27 FullDescription *sarifMessage `json:"fullDescription"` 28 Help *sarifMessage `json:"help"` 29 Properties *sarifProperties `json:"properties"` 30 DefaultConfiguration *sarifConfiguration `json:"defaultConfiguration"` 31} 32 33type sarifConfiguration struct { 34 Level sarifLevel `json:"level"` 35} 36 37type sarifArtifactLocation struct { 38 URI string `json:"uri"` 39} 40 41type sarifRegion struct { 42 StartLine uint64 `json:"startLine"` 43 EndLine uint64 `json:"endLine"` 44 StartColumn uint64 `json:"startColumn"` 45 EndColumn uint64 `json:"endColumn"` 46} 47 48type sarifPhysicalLocation struct { 49 ArtifactLocation *sarifArtifactLocation `json:"artifactLocation"` 50 Region *sarifRegion `json:"region"` 51} 52 53type sarifLocation struct { 54 PhysicalLocation *sarifPhysicalLocation `json:"physicalLocation"` 55} 56 57type sarifMessage struct { 58 Text string `json:"text"` 59} 60 61type sarifResult struct { 62 RuleID string `json:"ruleId"` 63 RuleIndex int `json:"ruleIndex"` 64 Level sarifLevel `json:"level"` 65 Message *sarifMessage `json:"message"` 66 Locations []*sarifLocation `json:"locations"` 67} 68 69type sarifDriver struct { 70 Name string `json:"name"` 71 InformationURI string `json:"informationUri"` 72 Rules []*sarifRule `json:"rules,omitempty"` 73} 74 75type sarifTool struct { 76 Driver *sarifDriver `json:"driver"` 77} 78 79type sarifRun struct { 80 Tool *sarifTool `json:"tool"` 81 Results []*sarifResult `json:"results"` 82} 83 84type sarifReport struct { 85 Schema string `json:"$schema"` 86 Version string `json:"version"` 87 Runs []*sarifRun `json:"runs"` 88} 89 90// buildSarifReport return SARIF report struct 91func buildSarifReport() *sarifReport { 92 return &sarifReport{ 93 Version: "2.1.0", 94 Schema: "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json", 95 Runs: []*sarifRun{}, 96 } 97} 98 99// buildSarifRule return SARIF rule field struct 100func buildSarifRule(issue *gosec.Issue) *sarifRule { 101 return &sarifRule{ 102 ID: fmt.Sprintf("%s (CWE-%s)", issue.RuleID, issue.Cwe.ID), 103 Name: issue.What, 104 ShortDescription: &sarifMessage{ 105 Text: issue.What, 106 }, 107 FullDescription: &sarifMessage{ 108 Text: issue.What, 109 }, 110 Help: &sarifMessage{ 111 Text: fmt.Sprintf("%s\nSeverity: %s\nConfidence: %s\nCWE: %s", issue.What, issue.Severity.String(), issue.Confidence.String(), issue.Cwe.URL), 112 }, 113 Properties: &sarifProperties{ 114 Tags: []string{fmt.Sprintf("CWE-%s", issue.Cwe.ID), issue.Severity.String()}, 115 }, 116 DefaultConfiguration: &sarifConfiguration{ 117 Level: getSarifLevel(issue.Severity.String()), 118 }, 119 } 120} 121 122// buildSarifLocation return SARIF location struct 123func buildSarifLocation(issue *gosec.Issue, rootPaths []string) (*sarifLocation, error) { 124 var filePath string 125 126 lines := strings.Split(issue.Line, "-") 127 startLine, err := strconv.ParseUint(lines[0], 10, 64) 128 if err != nil { 129 return nil, err 130 } 131 endLine := startLine 132 if len(lines) > 1 { 133 endLine, err = strconv.ParseUint(lines[1], 10, 64) 134 if err != nil { 135 return nil, err 136 } 137 } 138 139 col, err := strconv.ParseUint(issue.Col, 10, 64) 140 if err != nil { 141 return nil, err 142 } 143 144 for _, rootPath := range rootPaths { 145 if strings.HasPrefix(issue.File, rootPath) { 146 filePath = strings.Replace(issue.File, rootPath+"/", "", 1) 147 } 148 } 149 150 location := &sarifLocation{ 151 PhysicalLocation: &sarifPhysicalLocation{ 152 ArtifactLocation: &sarifArtifactLocation{ 153 URI: filePath, 154 }, 155 Region: &sarifRegion{ 156 StartLine: startLine, 157 EndLine: endLine, 158 StartColumn: col, 159 EndColumn: col, 160 }, 161 }, 162 } 163 164 return location, nil 165} 166 167// From https://docs.oasis-open.org/sarif/sarif/v2.0/csprd02/sarif-v2.0-csprd02.html#_Toc10127839 168// * "warning": The rule specified by ruleId was evaluated and a problem was found. 169// * "error": The rule specified by ruleId was evaluated and a serious problem was found. 170// * "note": The rule specified by ruleId was evaluated and a minor problem or an opportunity to improve the code was found. 171func getSarifLevel(s string) sarifLevel { 172 switch s { 173 case "LOW": 174 return sarifWarning 175 case "MEDIUM": 176 return sarifError 177 case "HIGH": 178 return sarifError 179 default: 180 return sarifNote 181 } 182} 183