gitleaks_test.go 22 KB

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