You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sarif.go 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package formatter
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "github.com/chavacava/garif"
  7. "github.com/mgechev/revive/lint"
  8. )
  9. // Sarif is an implementation of the Formatter interface
  10. // which formats revive failures into SARIF format.
  11. type Sarif struct {
  12. Metadata lint.FormatterMetadata
  13. }
  14. // Name returns the name of the formatter
  15. func (f *Sarif) Name() string {
  16. return "sarif"
  17. }
  18. const reviveSite = "https://revive.run"
  19. // Format formats the failures gotten from the lint.
  20. func (f *Sarif) Format(failures <-chan lint.Failure, cfg lint.Config) (string, error) {
  21. sarifLog := newReviveRunLog(cfg)
  22. for failure := range failures {
  23. sarifLog.AddResult(failure)
  24. }
  25. buf := new(bytes.Buffer)
  26. sarifLog.PrettyWrite(buf)
  27. return buf.String(), nil
  28. }
  29. type reviveRunLog struct {
  30. *garif.LogFile
  31. run *garif.Run
  32. rules map[string]lint.RuleConfig
  33. }
  34. func newReviveRunLog(cfg lint.Config) *reviveRunLog {
  35. run := garif.NewRun(garif.NewTool(garif.NewDriver("revive").WithInformationUri(reviveSite)))
  36. log := garif.NewLogFile([]*garif.Run{run}, garif.Version210)
  37. reviveLog := &reviveRunLog{
  38. log,
  39. run,
  40. cfg.Rules,
  41. }
  42. reviveLog.addRules(cfg.Rules)
  43. return reviveLog
  44. }
  45. func (l *reviveRunLog) addRules(cfg map[string]lint.RuleConfig) {
  46. for name, ruleCfg := range cfg {
  47. rule := garif.NewRule(name).WithHelpUri(reviveSite + "/r#" + name)
  48. setRuleProperties(rule, ruleCfg)
  49. driver := l.run.Tool.Driver
  50. if driver.Rules == nil {
  51. driver.Rules = []*garif.ReportingDescriptor{rule}
  52. return
  53. }
  54. driver.Rules = append(driver.Rules, rule)
  55. }
  56. }
  57. func (l *reviveRunLog) AddResult(failure lint.Failure) {
  58. positiveOrZero := func(x int) int {
  59. if x > 0 {
  60. return x
  61. }
  62. return 0
  63. }
  64. position := failure.Position
  65. filename := position.Start.Filename
  66. line := positiveOrZero(position.Start.Line - 1) // https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#def_line
  67. column := positiveOrZero(position.Start.Column - 1) // https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#def_column
  68. result := garif.NewResult(garif.NewMessageFromText(failure.Failure))
  69. location := garif.NewLocation().WithURI(filename).WithLineColumn(line, column)
  70. result.Locations = append(result.Locations, location)
  71. result.RuleId = failure.RuleName
  72. result.Level = l.rules[failure.RuleName].Severity
  73. l.run.Results = append(l.run.Results, result)
  74. }
  75. func setRuleProperties(sarifRule *garif.ReportingDescriptor, lintRule lint.RuleConfig) {
  76. arguments := make([]string, len(lintRule.Arguments))
  77. for i, arg := range lintRule.Arguments {
  78. arguments[i] = fmt.Sprintf("%+v", arg)
  79. }
  80. if len(arguments) > 0 {
  81. sarifRule.WithProperties("arguments", strings.Join(arguments, ","))
  82. }
  83. sarifRule.WithProperties("severity", string(lintRule.Severity))
  84. }