sarif.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package report
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "github.com/zricethezav/gitleaks/v8/config"
  7. )
  8. func writeSarif(cfg config.Config, findings []*Finding, w io.WriteCloser) error {
  9. sarif := Sarif{
  10. Schema: "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
  11. Version: "2.1.0",
  12. Runs: getRuns(cfg, findings),
  13. }
  14. encoder := json.NewEncoder(w)
  15. encoder.SetIndent("", " ")
  16. return encoder.Encode(sarif)
  17. }
  18. func getRuns(cfg config.Config, findings []*Finding) []Runs {
  19. return []Runs{
  20. {
  21. Tool: getTool(cfg),
  22. Results: getResults(findings),
  23. },
  24. }
  25. }
  26. func getTool(cfg config.Config) Tool {
  27. return Tool{
  28. Driver: Driver{
  29. Name: driver,
  30. SemanticVersion: version,
  31. Rules: getRules(cfg),
  32. },
  33. }
  34. }
  35. func getRules(cfg config.Config) []Rules {
  36. // TODO for _, rule := range cfg.Rules {
  37. var rules []Rules
  38. for _, rule := range cfg.Rules {
  39. rules = append(rules, Rules{
  40. ID: rule.RuleID,
  41. Name: rule.Description,
  42. Description: ShortDescription{
  43. Text: rule.Regex.String(),
  44. },
  45. })
  46. }
  47. return rules
  48. }
  49. func messageText(f *Finding) string {
  50. if f.Commit == "" {
  51. return fmt.Sprintf("%s has detected secret for file %s.", f.RuleID, f.File)
  52. }
  53. return fmt.Sprintf("%s has detected secret for file %s at commit %s.", f.RuleID, f.File, f.Commit)
  54. }
  55. func getResults(findings []*Finding) []Results {
  56. var results []Results
  57. for _, f := range findings {
  58. r := Results{
  59. Message: Message{
  60. Text: messageText(f),
  61. },
  62. RuleId: f.RuleID,
  63. Locations: getLocation(f),
  64. // This information goes in partial fingerprings until revision
  65. // data can be added somewhere else
  66. PartialFingerPrints: PartialFingerPrints{
  67. CommitSha: f.Commit,
  68. Email: f.Email,
  69. CommitMessage: f.Message,
  70. Date: f.Date,
  71. Author: f.Author,
  72. },
  73. }
  74. results = append(results, r)
  75. }
  76. return results
  77. }
  78. func getLocation(f *Finding) []Locations {
  79. return []Locations{
  80. {
  81. PhysicalLocation: PhysicalLocation{
  82. ArtifactLocation: ArtifactLocation{
  83. URI: f.File,
  84. },
  85. Region: Region{
  86. StartLine: f.StartLine,
  87. EndLine: f.EndLine,
  88. StartColumn: f.StartColumn,
  89. EndColumn: f.EndColumn,
  90. Snippet: Snippet{
  91. Text: f.Secret,
  92. },
  93. },
  94. },
  95. },
  96. }
  97. }
  98. type PartialFingerPrints struct {
  99. CommitSha string `json:"commitSha"`
  100. Email string `json:"email"`
  101. Author string `json:"author"`
  102. Date string `json:"date"`
  103. CommitMessage string `json:"commitMessage"`
  104. }
  105. type Sarif struct {
  106. Schema string `json:"$schema"`
  107. Version string `json:"version"`
  108. Runs []Runs `json:"runs"`
  109. }
  110. type ShortDescription struct {
  111. Text string `json:"text"`
  112. }
  113. type FullDescription struct {
  114. Text string `json:"text"`
  115. }
  116. type Rules struct {
  117. ID string `json:"id"`
  118. Name string `json:"name"`
  119. Description ShortDescription `json:"shortDescription"`
  120. }
  121. type Driver struct {
  122. Name string `json:"name"`
  123. SemanticVersion string `json:"semanticVersion"`
  124. Rules []Rules `json:"rules"`
  125. }
  126. type Tool struct {
  127. Driver Driver `json:"driver"`
  128. }
  129. type Message struct {
  130. Text string `json:"text"`
  131. }
  132. type ArtifactLocation struct {
  133. URI string `json:"uri"`
  134. }
  135. type Region struct {
  136. StartLine int `json:"startLine"`
  137. StartColumn int `json:"startColumn"`
  138. EndLine int `json:"endLine"`
  139. EndColumn int `json:"endColumn"`
  140. Snippet Snippet `json:"snippet"`
  141. }
  142. type Snippet struct {
  143. Text string `json:"text"`
  144. }
  145. type PhysicalLocation struct {
  146. ArtifactLocation ArtifactLocation `json:"artifactLocation"`
  147. Region Region `json:"region"`
  148. }
  149. type Locations struct {
  150. PhysicalLocation PhysicalLocation `json:"physicalLocation"`
  151. }
  152. type Results struct {
  153. Message Message `json:"message"`
  154. RuleId string `json:"ruleId"`
  155. Locations []Locations `json:"locations"`
  156. PartialFingerPrints `json:"partialFingerprints"`
  157. }
  158. type Runs struct {
  159. Tool Tool `json:"tool"`
  160. Results []Results `json:"results"`
  161. }
  162. func configToRules(cfg config.Config) []Rules {
  163. var rules []Rules
  164. for _, rule := range cfg.Rules {
  165. rules = append(rules, Rules{
  166. ID: rule.RuleID,
  167. Name: rule.Description,
  168. })
  169. }
  170. return rules
  171. }