leaks.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "os"
  9. "os/exec"
  10. "os/signal"
  11. "strings"
  12. "sync"
  13. "syscall"
  14. )
  15. type LeakElem struct {
  16. Line string `json:"line"`
  17. Commit string `json:"commit"`
  18. }
  19. func start(opts *Options, repoUrl string) {
  20. c := make(chan os.Signal, 2)
  21. signal.Notify(c, os.Interrupt, syscall.SIGTERM)
  22. err := exec.Command("git", "clone", repoUrl).Run()
  23. if err != nil {
  24. log.Fatalf("failed to clone repo %v", err)
  25. }
  26. repoName := strings.Split(repoUrl, "/")[4]
  27. if err := os.Chdir(repoName); err != nil {
  28. log.Fatal(err)
  29. }
  30. go func() {
  31. <-c
  32. cleanup(repoName)
  33. os.Exit(1)
  34. }()
  35. report := getLeaks(repoName)
  36. cleanup(repoName)
  37. reportJson, _ := json.MarshalIndent(report, "", "\t")
  38. err = ioutil.WriteFile(fmt.Sprintf("%s_leaks.json", repoName), reportJson, 0644)
  39. }
  40. func cleanup(repoName string) {
  41. if err := os.Chdir(appRoot); err != nil {
  42. log.Fatalf("failed cleaning up repo. Does the repo exist? %v", err)
  43. }
  44. err := exec.Command("rm", "-rf", repoName).Run()
  45. if err != nil {
  46. log.Fatal(err)
  47. }
  48. }
  49. func getLeaks(repoName string) []LeakElem {
  50. var (
  51. out []byte
  52. err error
  53. commitWG sync.WaitGroup
  54. gitLeakReceiverWG sync.WaitGroup
  55. concurrent = 100
  56. semaphoreChan = make(chan struct{}, concurrent)
  57. gitLeaks = make(chan LeakElem)
  58. report []LeakElem
  59. )
  60. go func(commitWG *sync.WaitGroup, gitLeakReceiverWG *sync.WaitGroup) {
  61. for gitLeak := range gitLeaks {
  62. fmt.Println(gitLeak)
  63. report = append(report, gitLeak)
  64. gitLeakReceiverWG.Done()
  65. }
  66. }(&commitWG, &gitLeakReceiverWG)
  67. out, err = exec.Command("git", "rev-list", "--all", "--remotes", "--topo-order").Output()
  68. if err != nil {
  69. log.Fatalf("error retrieving commits%v\n", err)
  70. }
  71. commits := bytes.Split(out, []byte("\n"))
  72. commitWG.Add(len(commits))
  73. for _, currCommitB := range commits {
  74. currCommit := string(currCommitB)
  75. go func(currCommit string, repoName string, commitWG *sync.WaitGroup, gitLeakReceiverWG *sync.WaitGroup) {
  76. defer commitWG.Done()
  77. var leakPrs bool
  78. if err := os.Chdir(fmt.Sprintf("%s/%s", appRoot, repoName)); err != nil {
  79. log.Fatal(err)
  80. }
  81. commitCmp := fmt.Sprintf("%s^!", currCommit)
  82. semaphoreChan <- struct{}{}
  83. out, err := exec.Command("git", "diff", commitCmp).Output()
  84. <-semaphoreChan
  85. if err != nil {
  86. return
  87. }
  88. lines := checkRegex(string(out))
  89. if len(lines) == 0 {
  90. return
  91. }
  92. for _, line := range lines {
  93. leakPrs = checkEntropy(line)
  94. if leakPrs {
  95. gitLeakReceiverWG.Add(1)
  96. gitLeaks <- LeakElem{line, currCommit}
  97. }
  98. }
  99. }(currCommit, repoName, &commitWG, &gitLeakReceiverWG)
  100. }
  101. commitWG.Wait()
  102. gitLeakReceiverWG.Wait()
  103. return report
  104. }