gitleaks_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path"
  7. "regexp"
  8. "strings"
  9. "testing"
  10. "github.com/franela/goblin"
  11. git "gopkg.in/src-d/go-git.v4"
  12. "gopkg.in/src-d/go-git.v4/storage/memory"
  13. )
  14. const testWhitelistCommit = `
  15. [[regexes]]
  16. description = "AWS"
  17. regex = '''AKIA[0-9A-Z]{16}'''
  18. [whitelist]
  19. commits = [
  20. "eaeffdc65b4c73ccb67e75d96bd8743be2c85973",
  21. ]
  22. `
  23. const testWhitelistFile = `
  24. [[regexes]]
  25. description = "AWS"
  26. regex = '''AKIA[0-9A-Z]{16}'''
  27. [whitelist]
  28. files = [
  29. ".go",
  30. ]
  31. `
  32. const testWhitelistBranch = `
  33. [[regexes]]
  34. description = "AWS"
  35. regex = '''AKIA[0-9A-Z]{16}'''
  36. [whitelist]
  37. branches = [
  38. "origin/master",
  39. ]
  40. `
  41. const testWhitelistRegex = `
  42. [[regexes]]
  43. description = "AWS"
  44. regex = '''AKIA[0-9A-Z]{16}'''
  45. [whitelist]
  46. regexes= [
  47. "AKIA",
  48. ]
  49. `
  50. const testWhitelistRepo = `
  51. [[regexes]]
  52. description = "AWS"
  53. regex = '''AKIA[0-9A-Z]{16}'''
  54. [whitelist]
  55. repos = [
  56. "gronit",
  57. ]
  58. `
  59. const testEntropyRange = `
  60. [misc]
  61. entropy = [
  62. "7.5-8.0",
  63. "3.3-3.4",
  64. ]
  65. `
  66. const testBadEntropyRange = `
  67. [misc]
  68. entropy = [
  69. "8.0-3.0",
  70. ]
  71. `
  72. const testBadEntropyRange2 = `
  73. [misc]
  74. entropy = [
  75. "8.0-8.9",
  76. ]
  77. `
  78. var benchmarkRepo *RepoDescriptor
  79. var benchmarkLeaksRepo *RepoDescriptor
  80. func getBenchmarkLeaksRepo() *RepoDescriptor {
  81. if benchmarkLeaksRepo != nil {
  82. return benchmarkLeaksRepo
  83. }
  84. leaksR, _ := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
  85. URL: "https://github.com/gitleakstest/gronit.git",
  86. })
  87. benchmarkLeaksRepo = &RepoDescriptor{
  88. repository: leaksR,
  89. }
  90. return benchmarkLeaksRepo
  91. }
  92. func getBenchmarkRepo() *RepoDescriptor {
  93. if benchmarkRepo != nil {
  94. return benchmarkRepo
  95. }
  96. bmRepo, _ := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
  97. URL: "https://github.com/apple/swift-package-manager.git",
  98. })
  99. benchmarkRepo = &RepoDescriptor{
  100. repository: bmRepo,
  101. }
  102. return benchmarkRepo
  103. }
  104. func TestGetRepo(t *testing.T) {
  105. var err error
  106. dir, err = ioutil.TempDir("", "gitleaksTestRepo")
  107. defer os.RemoveAll(dir)
  108. if err != nil {
  109. panic(err)
  110. }
  111. _, err = git.PlainClone(dir, false, &git.CloneOptions{
  112. URL: "https://github.com/gitleakstest/gronit",
  113. })
  114. if err != nil {
  115. panic(err)
  116. }
  117. var tests = []struct {
  118. testOpts Options
  119. description string
  120. expectedErrMsg string
  121. }{
  122. {
  123. testOpts: Options{
  124. Repo: "https://github.com/gitleakstest/gronit",
  125. },
  126. description: "test plain clone remote repo",
  127. expectedErrMsg: "",
  128. },
  129. {
  130. testOpts: Options{
  131. Repo: "https://github.com/gitleakstest/gronit",
  132. Disk: true,
  133. },
  134. description: "test on disk clone remote repo",
  135. expectedErrMsg: "",
  136. },
  137. {
  138. testOpts: Options{
  139. RepoPath: dir,
  140. },
  141. description: "test local clone repo",
  142. expectedErrMsg: "",
  143. },
  144. {
  145. testOpts: Options{
  146. Repo: "https://github.com/gitleakstest/nope",
  147. },
  148. description: "test no repo",
  149. expectedErrMsg: "authentication required",
  150. },
  151. {
  152. testOpts: Options{
  153. Repo: "https://github.com/gitleakstest/private",
  154. IncludePrivate: true,
  155. },
  156. description: "test private repo",
  157. expectedErrMsg: "invalid auth method",
  158. },
  159. {
  160. testOpts: Options{
  161. Repo: "https://github.com/gitleakstest/private",
  162. IncludePrivate: true,
  163. Disk: true,
  164. },
  165. description: "test private repo",
  166. expectedErrMsg: "invalid auth method",
  167. },
  168. }
  169. g := goblin.Goblin(t)
  170. for _, test := range tests {
  171. g.Describe("TestGetRepo", func() {
  172. g.It(test.description, func() {
  173. opts = test.testOpts
  174. _, err := cloneRepo()
  175. if err != nil {
  176. g.Assert(err.Error()).Equal(test.expectedErrMsg)
  177. }
  178. })
  179. })
  180. }
  181. }
  182. func TestRun(t *testing.T) {
  183. var err error
  184. configsDir := testTomlLoader()
  185. dir, err = ioutil.TempDir("", "gitleaksTestOwner")
  186. defer os.RemoveAll(dir)
  187. if err != nil {
  188. panic(err)
  189. }
  190. git.PlainClone(dir+"/gronit", false, &git.CloneOptions{
  191. URL: "https://github.com/gitleakstest/gronit",
  192. })
  193. git.PlainClone(dir+"/h1domains", false, &git.CloneOptions{
  194. URL: "https://github.com/gitleakstest/h1domains",
  195. })
  196. var tests = []struct {
  197. testOpts Options
  198. description string
  199. expectedErrMsg string
  200. whiteListRepos []string
  201. numLeaks int
  202. configPath string
  203. commitPerPage int
  204. }{
  205. {
  206. testOpts: Options{
  207. GithubUser: "gitleakstest",
  208. },
  209. description: "test github user",
  210. numLeaks: 2,
  211. expectedErrMsg: "",
  212. },
  213. {
  214. testOpts: Options{
  215. GithubUser: "gitleakstest",
  216. Disk: true,
  217. },
  218. description: "test github user on disk ",
  219. numLeaks: 2,
  220. expectedErrMsg: "",
  221. },
  222. {
  223. testOpts: Options{
  224. GithubOrg: "gitleakstestorg",
  225. },
  226. description: "test github org",
  227. numLeaks: 2,
  228. expectedErrMsg: "",
  229. },
  230. {
  231. testOpts: Options{
  232. GithubOrg: "gitleakstestorg",
  233. Disk: true,
  234. },
  235. description: "test org on disk",
  236. numLeaks: 2,
  237. expectedErrMsg: "",
  238. },
  239. {
  240. testOpts: Options{
  241. OwnerPath: dir,
  242. },
  243. description: "test owner path",
  244. numLeaks: 2,
  245. expectedErrMsg: "",
  246. },
  247. {
  248. testOpts: Options{
  249. GithubOrg: "gitleakstestorg",
  250. IncludePrivate: true,
  251. SSHKey: "reallyreallyreallyreallywrongpath",
  252. },
  253. description: "test private org no ssh",
  254. numLeaks: 0,
  255. expectedErrMsg: "unable to generate ssh key: open reallyreallyreallyreallywrongpath: no such file or directory",
  256. },
  257. {
  258. testOpts: Options{
  259. Repo: "https://github.com/gitleakstest/gronit.git",
  260. },
  261. description: "test leak",
  262. numLeaks: 2,
  263. expectedErrMsg: "",
  264. },
  265. {
  266. testOpts: Options{
  267. Repo: "https://github.com/gitleakstest/h1domains.git",
  268. },
  269. description: "test clean",
  270. numLeaks: 0,
  271. expectedErrMsg: "",
  272. },
  273. {
  274. testOpts: Options{
  275. Repo: "https://github.com/gitleakstest/empty.git",
  276. },
  277. description: "test empty",
  278. numLeaks: 0,
  279. expectedErrMsg: "reference not found",
  280. },
  281. {
  282. testOpts: Options{
  283. GithubOrg: "gitleakstestorg",
  284. },
  285. description: "test github org, whitelist repo",
  286. numLeaks: 0,
  287. expectedErrMsg: "",
  288. configPath: path.Join(configsDir, "repo"),
  289. },
  290. {
  291. testOpts: Options{
  292. GithubOrg: "gitleakstestorg",
  293. ExcludeForks: true,
  294. },
  295. description: "test github org, exclude forks",
  296. numLeaks: 0,
  297. expectedErrMsg: "",
  298. },
  299. {
  300. testOpts: Options{
  301. GithubPR: "https://github.com/gitleakstest/gronit/pull/1",
  302. },
  303. description: "test github pr",
  304. numLeaks: 4,
  305. expectedErrMsg: "",
  306. },
  307. {
  308. testOpts: Options{
  309. GithubPR: "https://github.com/gitleakstest/gronit/pull/1",
  310. },
  311. description: "test github pr",
  312. numLeaks: 4,
  313. expectedErrMsg: "",
  314. commitPerPage: 1,
  315. },
  316. }
  317. g := goblin.Goblin(t)
  318. for _, test := range tests {
  319. g.Describe("TestRun", func() {
  320. g.It(test.description, func() {
  321. if test.configPath != "" {
  322. os.Setenv("GITLEAKS_CONFIG", test.configPath)
  323. }
  324. if test.commitPerPage != 0 {
  325. githubPages = test.commitPerPage
  326. }
  327. opts = test.testOpts
  328. leaks, err := run()
  329. if err != nil {
  330. g.Assert(err.Error()).Equal(test.expectedErrMsg)
  331. }
  332. g.Assert(len(leaks)).Equal(test.numLeaks)
  333. githubPages = 100
  334. })
  335. })
  336. }
  337. }
  338. func TestWriteReport(t *testing.T) {
  339. tmpDir, _ := ioutil.TempDir("", "reportDir")
  340. reportJSON := path.Join(tmpDir, "report.json")
  341. reportJASON := path.Join(tmpDir, "report.jason")
  342. reportVOID := path.Join("thereIsNoWay", "thisReportWillGetWritten.json")
  343. reportCSV := path.Join(tmpDir, "report.csv")
  344. defer os.RemoveAll(tmpDir)
  345. leaks := []Leak{
  346. {
  347. Line: "eat",
  348. Commit: "your",
  349. Offender: "veggies",
  350. Type: "and",
  351. Message: "get",
  352. Author: "some",
  353. File: "sleep",
  354. Branch: "thxu",
  355. },
  356. }
  357. var tests = []struct {
  358. leaks []Leak
  359. reportFile string
  360. fileName string
  361. description string
  362. testOpts Options
  363. expectedErrMsg string
  364. }{
  365. {
  366. leaks: leaks,
  367. reportFile: reportJSON,
  368. fileName: "report.json",
  369. description: "can we write a json file",
  370. testOpts: Options{
  371. Report: reportJSON,
  372. },
  373. },
  374. {
  375. leaks: leaks,
  376. reportFile: reportCSV,
  377. fileName: "report.csv",
  378. description: "can we write a csv file",
  379. testOpts: Options{
  380. Report: reportCSV,
  381. },
  382. },
  383. {
  384. leaks: leaks,
  385. reportFile: reportJASON,
  386. fileName: "report.jason",
  387. description: "bad file",
  388. expectedErrMsg: "Report should be a .json or .csv file",
  389. testOpts: Options{
  390. Report: reportJASON,
  391. },
  392. },
  393. {
  394. leaks: leaks,
  395. reportFile: reportVOID,
  396. fileName: "report.jason",
  397. description: "bad dir",
  398. expectedErrMsg: "thereIsNoWay does not exist",
  399. testOpts: Options{
  400. Report: reportVOID,
  401. },
  402. },
  403. }
  404. g := goblin.Goblin(t)
  405. for _, test := range tests {
  406. g.Describe("TestWriteReport", func() {
  407. g.It(test.description, func() {
  408. opts = test.testOpts
  409. err := optsGuard()
  410. if err != nil {
  411. g.Assert(err.Error()).Equal(test.expectedErrMsg)
  412. } else {
  413. writeReport(test.leaks)
  414. f, _ := os.Stat(test.reportFile)
  415. g.Assert(f.Name()).Equal(test.fileName)
  416. }
  417. })
  418. })
  419. }
  420. }
  421. func testTomlLoader() string {
  422. tmpDir, _ := ioutil.TempDir("", "whiteListConfigs")
  423. ioutil.WriteFile(path.Join(tmpDir, "regex"), []byte(testWhitelistRegex), 0644)
  424. ioutil.WriteFile(path.Join(tmpDir, "branch"), []byte(testWhitelistBranch), 0644)
  425. ioutil.WriteFile(path.Join(tmpDir, "commit"), []byte(testWhitelistCommit), 0644)
  426. ioutil.WriteFile(path.Join(tmpDir, "file"), []byte(testWhitelistFile), 0644)
  427. ioutil.WriteFile(path.Join(tmpDir, "repo"), []byte(testWhitelistRepo), 0644)
  428. ioutil.WriteFile(path.Join(tmpDir, "entropy"), []byte(testEntropyRange), 0644)
  429. ioutil.WriteFile(path.Join(tmpDir, "badEntropy"), []byte(testBadEntropyRange), 0644)
  430. ioutil.WriteFile(path.Join(tmpDir, "badEntropy2"), []byte(testBadEntropyRange2), 0644)
  431. return tmpDir
  432. }
  433. func TestAuditRepo(t *testing.T) {
  434. var leaks []Leak
  435. err := loadToml()
  436. configsDir := testTomlLoader()
  437. defer os.RemoveAll(configsDir)
  438. if err != nil {
  439. panic(err)
  440. }
  441. leaksR, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
  442. URL: "https://github.com/gitleakstest/gronit.git",
  443. })
  444. if err != nil {
  445. panic(err)
  446. }
  447. leaksRepo := &RepoDescriptor{
  448. repository: leaksR,
  449. name: "gronit",
  450. }
  451. cleanR, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
  452. URL: "https://github.com/gitleakstest/h1domains.git",
  453. })
  454. if err != nil {
  455. panic(err)
  456. }
  457. cleanRepo := &RepoDescriptor{
  458. repository: cleanR,
  459. name: "h1domains",
  460. }
  461. var tests = []struct {
  462. testOpts Options
  463. description string
  464. expectedErrMsg string
  465. numLeaks int
  466. repo *RepoDescriptor
  467. whiteListFiles []*regexp.Regexp
  468. whiteListCommits map[string]bool
  469. whiteListBranches []string
  470. whiteListRepos []*regexp.Regexp
  471. whiteListRegexes []*regexp.Regexp
  472. configPath string
  473. }{
  474. {
  475. repo: leaksRepo,
  476. description: "two leaks present",
  477. numLeaks: 2,
  478. },
  479. {
  480. repo: leaksRepo,
  481. description: "two leaks present limit goroutines",
  482. numLeaks: 2,
  483. testOpts: Options{
  484. MaxGoRoutines: 4,
  485. },
  486. },
  487. {
  488. repo: leaksRepo,
  489. description: "audit specific bad branch",
  490. numLeaks: 2,
  491. testOpts: Options{
  492. Branch: "master",
  493. },
  494. },
  495. {
  496. repo: leaksRepo,
  497. description: "audit specific good branch",
  498. numLeaks: 0,
  499. testOpts: Options{
  500. Branch: "dev",
  501. },
  502. },
  503. {
  504. repo: leaksRepo,
  505. description: "audit all branch",
  506. numLeaks: 6,
  507. testOpts: Options{
  508. AuditAllRefs: true,
  509. },
  510. },
  511. {
  512. repo: leaksRepo,
  513. description: "audit all branch whitelist 1",
  514. numLeaks: 4,
  515. testOpts: Options{
  516. AuditAllRefs: true,
  517. },
  518. whiteListBranches: []string{
  519. "origin/master",
  520. },
  521. },
  522. {
  523. repo: leaksRepo,
  524. description: "two leaks present whitelist AWS.. no leaks",
  525. whiteListRegexes: []*regexp.Regexp{
  526. regexp.MustCompile("AKIA"),
  527. },
  528. numLeaks: 0,
  529. },
  530. {
  531. repo: leaksRepo,
  532. description: "two leaks present limit goroutines",
  533. numLeaks: 2,
  534. },
  535. {
  536. repo: cleanRepo,
  537. description: "no leaks present",
  538. numLeaks: 0,
  539. },
  540. {
  541. repo: leaksRepo,
  542. description: "two leaks present whitelist go files",
  543. whiteListFiles: []*regexp.Regexp{
  544. regexp.MustCompile(".go"),
  545. },
  546. numLeaks: 0,
  547. },
  548. {
  549. repo: leaksRepo,
  550. description: "two leaks present whitelist bad commit",
  551. whiteListCommits: map[string]bool{
  552. "eaeffdc65b4c73ccb67e75d96bd8743be2c85973": true,
  553. },
  554. numLeaks: 1,
  555. },
  556. {
  557. repo: leaksRepo,
  558. description: "redact",
  559. testOpts: Options{
  560. Redact: true,
  561. },
  562. numLeaks: 2,
  563. },
  564. {
  565. repo: leaksRepo,
  566. description: "toml whitelist regex",
  567. configPath: path.Join(configsDir, "regex"),
  568. numLeaks: 0,
  569. },
  570. {
  571. repo: leaksRepo,
  572. description: "toml whitelist branch",
  573. configPath: path.Join(configsDir, "branch"),
  574. testOpts: Options{
  575. AuditAllRefs: true,
  576. },
  577. numLeaks: 4,
  578. },
  579. {
  580. repo: leaksRepo,
  581. description: "toml whitelist file",
  582. configPath: path.Join(configsDir, "file"),
  583. numLeaks: 0,
  584. },
  585. {
  586. repo: leaksRepo,
  587. description: "toml whitelist commit",
  588. configPath: path.Join(configsDir, "commit"),
  589. numLeaks: 1,
  590. },
  591. {
  592. repo: leaksRepo,
  593. description: "audit whitelist repo",
  594. numLeaks: 0,
  595. whiteListRepos: []*regexp.Regexp{
  596. regexp.MustCompile("gronit"),
  597. },
  598. },
  599. {
  600. repo: leaksRepo,
  601. description: "toml whitelist repo",
  602. numLeaks: 0,
  603. configPath: path.Join(configsDir, "repo"),
  604. },
  605. {
  606. repo: leaksRepo,
  607. description: "leaks present with entropy",
  608. testOpts: Options{
  609. Entropy: 4.7,
  610. },
  611. numLeaks: 7,
  612. },
  613. {
  614. repo: leaksRepo,
  615. description: "Audit until specific commit",
  616. numLeaks: 1,
  617. testOpts: Options{
  618. Commit: "f6839959b7bbdcd23008f1fb16f797f35bcd3a0c",
  619. },
  620. },
  621. {
  622. repo: leaksRepo,
  623. description: "commit depth = 1, no leaks",
  624. numLeaks: 0,
  625. testOpts: Options{
  626. Depth: 1,
  627. },
  628. },
  629. {
  630. repo: leaksRepo,
  631. description: "commit depth = 2, one leak",
  632. numLeaks: 1,
  633. testOpts: Options{
  634. Depth: 2,
  635. },
  636. },
  637. {
  638. repo: leaksRepo,
  639. description: "toml entropy range",
  640. numLeaks: 422,
  641. configPath: path.Join(configsDir, "entropy"),
  642. },
  643. {
  644. repo: leaksRepo,
  645. description: "toml bad entropy range",
  646. numLeaks: 0,
  647. configPath: path.Join(configsDir, "badEntropy"),
  648. expectedErrMsg: "entropy range must be ascending",
  649. },
  650. {
  651. repo: leaksRepo,
  652. description: "toml bad entropy2 range",
  653. numLeaks: 0,
  654. configPath: path.Join(configsDir, "badEntropy2"),
  655. expectedErrMsg: "invalid entropy ranges, must be within 0.0-8.0",
  656. },
  657. }
  658. whiteListCommits = make(map[string]bool)
  659. g := goblin.Goblin(t)
  660. for _, test := range tests {
  661. g.Describe("TestAuditRepo", func() {
  662. g.It(test.description, func() {
  663. opts = test.testOpts
  664. // settin da globs
  665. if test.whiteListFiles != nil {
  666. whiteListFiles = test.whiteListFiles
  667. } else {
  668. whiteListFiles = nil
  669. }
  670. if test.whiteListCommits != nil {
  671. whiteListCommits = test.whiteListCommits
  672. } else {
  673. whiteListCommits = nil
  674. }
  675. if test.whiteListBranches != nil {
  676. whiteListBranches = test.whiteListBranches
  677. } else {
  678. whiteListBranches = nil
  679. }
  680. if test.whiteListRegexes != nil {
  681. whiteListRegexes = test.whiteListRegexes
  682. } else {
  683. whiteListRegexes = nil
  684. }
  685. if test.whiteListRepos != nil {
  686. whiteListRepos = test.whiteListRepos
  687. } else {
  688. whiteListRepos = nil
  689. }
  690. skip := false
  691. // config paths
  692. if test.configPath != "" {
  693. os.Setenv("GITLEAKS_CONFIG", test.configPath)
  694. err := loadToml()
  695. if err != nil {
  696. g.Assert(err.Error()).Equal(test.expectedErrMsg)
  697. skip = true
  698. }
  699. }
  700. if !skip {
  701. leaks, err = auditGitRepo(test.repo)
  702. if opts.Redact {
  703. g.Assert(leaks[0].Offender).Equal("REDACTED")
  704. }
  705. g.Assert(len(leaks)).Equal(test.numLeaks)
  706. }
  707. })
  708. })
  709. }
  710. }
  711. func TestOptionGuard(t *testing.T) {
  712. var tests = []struct {
  713. testOpts Options
  714. githubToken bool
  715. description string
  716. expectedErrMsg string
  717. expectedErrMsgFuzzy string
  718. }{
  719. {
  720. testOpts: Options{},
  721. description: "default no opts",
  722. expectedErrMsg: "",
  723. },
  724. {
  725. testOpts: Options{
  726. IncludePrivate: true,
  727. GithubOrg: "fakeOrg",
  728. },
  729. description: "private org no githubtoken",
  730. expectedErrMsg: "user/organization private repos require env var GITHUB_TOKEN to be set",
  731. githubToken: false,
  732. },
  733. {
  734. testOpts: Options{
  735. IncludePrivate: true,
  736. GithubUser: "fakeUser",
  737. },
  738. description: "private user no githubtoken",
  739. expectedErrMsg: "user/organization private repos require env var GITHUB_TOKEN to be set",
  740. githubToken: false,
  741. },
  742. {
  743. testOpts: Options{
  744. IncludePrivate: true,
  745. GithubUser: "fakeUser",
  746. GithubOrg: "fakeOrg",
  747. },
  748. description: "double owner",
  749. expectedErrMsg: "github user and organization set",
  750. },
  751. {
  752. testOpts: Options{
  753. IncludePrivate: true,
  754. GithubOrg: "fakeOrg",
  755. OwnerPath: "/dev/null",
  756. },
  757. description: "local and remote target",
  758. expectedErrMsg: "github organization set and local owner path",
  759. },
  760. {
  761. testOpts: Options{
  762. IncludePrivate: true,
  763. GithubUser: "fakeUser",
  764. OwnerPath: "/dev/null",
  765. },
  766. description: "local and remote target",
  767. expectedErrMsg: "github user set and local owner path",
  768. },
  769. {
  770. testOpts: Options{
  771. GithubUser: "fakeUser",
  772. SingleSearch: "*/./....",
  773. },
  774. description: "single search invalid regex gaurd",
  775. expectedErrMsgFuzzy: "unable to compile regex: */./...., ",
  776. },
  777. {
  778. testOpts: Options{
  779. GithubUser: "fakeUser",
  780. SingleSearch: "mystring",
  781. },
  782. description: "single search regex gaurd",
  783. expectedErrMsg: "",
  784. },
  785. {
  786. testOpts: Options{
  787. GithubOrg: "fakeOrg",
  788. Entropy: 9,
  789. },
  790. description: "Invalid entropy level guard",
  791. expectedErrMsg: "The maximum level of entropy is 8",
  792. },
  793. }
  794. g := goblin.Goblin(t)
  795. for _, test := range tests {
  796. g.Describe("Test Option Gaurd", func() {
  797. g.It(test.description, func() {
  798. os.Clearenv()
  799. opts = test.testOpts
  800. if test.githubToken {
  801. os.Setenv("GITHUB_TOKEN", "fakeToken")
  802. }
  803. err := optsGuard()
  804. if err != nil {
  805. if test.expectedErrMsgFuzzy != "" {
  806. g.Assert(strings.Contains(err.Error(), test.expectedErrMsgFuzzy)).Equal(true)
  807. } else {
  808. g.Assert(err.Error()).Equal(test.expectedErrMsg)
  809. }
  810. } else {
  811. g.Assert("").Equal(test.expectedErrMsg)
  812. }
  813. })
  814. })
  815. }
  816. }
  817. func TestLoadToml(t *testing.T) {
  818. tmpDir, _ := ioutil.TempDir("", "gitleaksTestConfigDir")
  819. defer os.RemoveAll(tmpDir)
  820. err := ioutil.WriteFile(path.Join(tmpDir, "gitleaksConfig"), []byte(defaultConfig), 0644)
  821. if err != nil {
  822. panic(err)
  823. }
  824. configPath := path.Join(tmpDir, "gitleaksConfig")
  825. noConfigPath := path.Join(tmpDir, "gitleaksConfigNope")
  826. var tests = []struct {
  827. testOpts Options
  828. description string
  829. configPath string
  830. expectedErrMsg string
  831. singleSearch bool
  832. }{
  833. {
  834. testOpts: Options{
  835. ConfigPath: configPath,
  836. },
  837. description: "path to config",
  838. },
  839. {
  840. testOpts: Options{},
  841. description: "env var path to no config",
  842. singleSearch: true,
  843. },
  844. {
  845. testOpts: Options{
  846. ConfigPath: noConfigPath,
  847. },
  848. description: "no path to config",
  849. expectedErrMsg: fmt.Sprintf("no gitleaks config at %s", noConfigPath),
  850. },
  851. {
  852. testOpts: Options{},
  853. description: "env var path to config",
  854. configPath: configPath,
  855. expectedErrMsg: "",
  856. },
  857. {
  858. testOpts: Options{},
  859. description: "env var path to no config",
  860. configPath: noConfigPath,
  861. expectedErrMsg: fmt.Sprintf("problem loading config: open %s: no such file or directory", noConfigPath),
  862. },
  863. }
  864. g := goblin.Goblin(t)
  865. for _, test := range tests {
  866. g.Describe("TestLoadToml", func() {
  867. g.It(test.description, func() {
  868. opts = test.testOpts
  869. if test.singleSearch {
  870. singleSearchRegex = regexp.MustCompile("test")
  871. } else {
  872. singleSearchRegex = nil
  873. }
  874. if test.configPath != "" {
  875. os.Setenv("GITLEAKS_CONFIG", test.configPath)
  876. } else {
  877. os.Clearenv()
  878. }
  879. err := loadToml()
  880. if err != nil {
  881. g.Assert(err.Error()).Equal(test.expectedErrMsg)
  882. } else {
  883. g.Assert("").Equal(test.expectedErrMsg)
  884. }
  885. })
  886. })
  887. }
  888. }
  889. func BenchmarkAuditRepo1Proc(b *testing.B) {
  890. loadToml()
  891. opts.MaxGoRoutines = 1
  892. benchmarkRepo = getBenchmarkRepo()
  893. for n := 0; n < b.N; n++ {
  894. auditGitRepo(benchmarkRepo)
  895. }
  896. }
  897. func BenchmarkAuditRepo2Proc(b *testing.B) {
  898. loadToml()
  899. opts.MaxGoRoutines = 2
  900. benchmarkRepo = getBenchmarkRepo()
  901. for n := 0; n < b.N; n++ {
  902. auditGitRepo(benchmarkRepo)
  903. }
  904. }
  905. func BenchmarkAuditRepo4Proc(b *testing.B) {
  906. loadToml()
  907. opts.MaxGoRoutines = 4
  908. benchmarkRepo = getBenchmarkRepo()
  909. for n := 0; n < b.N; n++ {
  910. auditGitRepo(benchmarkRepo)
  911. }
  912. }
  913. func BenchmarkAuditRepo8Proc(b *testing.B) {
  914. loadToml()
  915. opts.MaxGoRoutines = 8
  916. benchmarkRepo = getBenchmarkRepo()
  917. for n := 0; n < b.N; n++ {
  918. auditGitRepo(benchmarkRepo)
  919. }
  920. }
  921. func BenchmarkAuditRepo10Proc(b *testing.B) {
  922. loadToml()
  923. opts.MaxGoRoutines = 10
  924. benchmarkRepo = getBenchmarkRepo()
  925. for n := 0; n < b.N; n++ {
  926. auditGitRepo(benchmarkRepo)
  927. }
  928. }
  929. func BenchmarkAuditRepo100Proc(b *testing.B) {
  930. loadToml()
  931. opts.MaxGoRoutines = 100
  932. benchmarkRepo = getBenchmarkRepo()
  933. for n := 0; n < b.N; n++ {
  934. auditGitRepo(benchmarkRepo)
  935. }
  936. }
  937. func BenchmarkAuditRepo1000Proc(b *testing.B) {
  938. loadToml()
  939. opts.MaxGoRoutines = 1000
  940. benchmarkRepo = getBenchmarkRepo()
  941. for n := 0; n < b.N; n++ {
  942. auditGitRepo(benchmarkRepo)
  943. }
  944. }
  945. func BenchmarkAuditLeakRepo1Proc(b *testing.B) {
  946. loadToml()
  947. opts.MaxGoRoutines = 1
  948. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  949. for n := 0; n < b.N; n++ {
  950. auditGitRepo(benchmarkRepo)
  951. }
  952. }
  953. func BenchmarkAuditLeakRepo2Proc(b *testing.B) {
  954. loadToml()
  955. opts.MaxGoRoutines = 2
  956. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  957. for n := 0; n < b.N; n++ {
  958. auditGitRepo(benchmarkRepo)
  959. }
  960. }
  961. func BenchmarkAuditLeakRepo4Proc(b *testing.B) {
  962. loadToml()
  963. opts.MaxGoRoutines = 4
  964. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  965. for n := 0; n < b.N; n++ {
  966. auditGitRepo(benchmarkRepo)
  967. }
  968. }
  969. func BenchmarkAuditLeakRepo8Proc(b *testing.B) {
  970. loadToml()
  971. opts.MaxGoRoutines = 8
  972. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  973. for n := 0; n < b.N; n++ {
  974. auditGitRepo(benchmarkRepo)
  975. }
  976. }
  977. func BenchmarkAuditLeakRepo10Proc(b *testing.B) {
  978. loadToml()
  979. opts.MaxGoRoutines = 10
  980. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  981. for n := 0; n < b.N; n++ {
  982. auditGitRepo(benchmarkRepo)
  983. }
  984. }
  985. func BenchmarkAuditLeakRepo100Proc(b *testing.B) {
  986. loadToml()
  987. opts.MaxGoRoutines = 100
  988. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  989. for n := 0; n < b.N; n++ {
  990. auditGitRepo(benchmarkRepo)
  991. }
  992. }
  993. func BenchmarkAuditLeakRepo1000Proc(b *testing.B) {
  994. loadToml()
  995. opts.MaxGoRoutines = 1000
  996. benchmarkLeaksRepo = getBenchmarkLeaksRepo()
  997. for n := 0; n < b.N; n++ {
  998. auditGitRepo(benchmarkRepo)
  999. }
  1000. }