scan_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. package scan
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "reflect"
  8. "runtime"
  9. "sort"
  10. "testing"
  11. "github.com/zricethezav/gitleaks/v7/config"
  12. "github.com/zricethezav/gitleaks/v7/options"
  13. "github.com/sergi/go-diff/diffmatchpatch"
  14. )
  15. const testRepoBase = "../test_data/test_repos/"
  16. func TestScan(t *testing.T) {
  17. moveDotGit("dotGit", ".git")
  18. defer moveDotGit(".git", "dotGit")
  19. tests := []struct {
  20. description string
  21. opts options.Options
  22. wantPath string
  23. wantErr error
  24. wantScanErr error
  25. emptyRepo bool
  26. wantEmpty bool
  27. }{
  28. {
  29. description: "test local repo one aws leak",
  30. opts: options.Options{
  31. Path: "../test_data/test_repos/test_repo_1",
  32. Report: "../test_data/test_local_repo_one_aws_leak.json.got",
  33. ReportFormat: "json",
  34. },
  35. wantPath: "../test_data/test_local_repo_one_aws_leak.json",
  36. },
  37. {
  38. description: "test local repo one aws leak threaded",
  39. opts: options.Options{
  40. Threads: runtime.GOMAXPROCS(0),
  41. Path: "../test_data/test_repos/test_repo_1",
  42. Report: "../test_data/test_local_repo_one_aws_leak.json.got",
  43. ReportFormat: "json",
  44. },
  45. wantPath: "../test_data/test_local_repo_one_aws_leak.json",
  46. },
  47. {
  48. description: "test non existent repo",
  49. opts: options.Options{
  50. Path: "../test_data/test_repos/no_repo_here",
  51. ReportFormat: "json",
  52. },
  53. wantErr: fmt.Errorf("stat ../test_data/test_repos/no_repo_here: no such file or directory"),
  54. emptyRepo: true,
  55. },
  56. {
  57. description: "test local repo one aws leak allowlisted",
  58. opts: options.Options{
  59. Path: "../test_data/test_repos/test_repo_1",
  60. ReportFormat: "json",
  61. ConfigPath: "../test_data/test_configs/aws_key_allowlist_python_files.toml",
  62. },
  63. wantEmpty: true,
  64. },
  65. {
  66. description: "test local repo two leaks",
  67. opts: options.Options{
  68. Path: "../test_data/test_repos/test_repo_2",
  69. Report: "../test_data/test_local_repo_two_leaks.json.got",
  70. ReportFormat: "json",
  71. },
  72. wantPath: "../test_data/test_local_repo_two_leaks.json",
  73. },
  74. {
  75. description: "test local repo two leaks from Commit",
  76. opts: options.Options{
  77. Path: "../test_data/test_repos/test_repo_2",
  78. Report: "../test_data/test_local_repo_two_leaks_commit_from.json.got",
  79. ReportFormat: "json",
  80. CommitFrom: "996865bb912f3bc45898a370a13aadb315014b55",
  81. },
  82. wantPath: "../test_data/test_local_repo_two_leaks_commit_from.json",
  83. },
  84. {
  85. description: "test local repo two leaks to Commit",
  86. opts: options.Options{
  87. Path: "../test_data/test_repos/test_repo_2",
  88. Report: "../test_data/test_local_repo_two_leaks_commit_to.json.got",
  89. ReportFormat: "json",
  90. CommitTo: "996865bb912f3bc45898a370a13aadb315014b55",
  91. },
  92. wantPath: "../test_data/test_local_repo_two_leaks_commit_to.json",
  93. },
  94. {
  95. description: "test local repo two leaks to from Commit",
  96. opts: options.Options{
  97. Path: "../test_data/test_repos/test_repo_2",
  98. Report: "../test_data/test_local_repo_two_leaks_commit_to_from.json.got",
  99. ReportFormat: "json",
  100. CommitFrom: "d8ac0b73aeeb45843319cdc5ce506516eb49bf7a",
  101. CommitTo: "51f6dcf6b89b93f4075ba92c400b075631a6cc93",
  102. },
  103. wantPath: "../test_data/test_local_repo_two_leaks_commit_to_from.json",
  104. },
  105. {
  106. description: "test local repo two leaks list Commits",
  107. opts: options.Options{
  108. Path: "../test_data/test_repos/test_repo_2",
  109. Report: "../test_data/test_local_repo_two_leaks_commit_range.json.got",
  110. ReportFormat: "json",
  111. Commits: "d8ac0b73aeeb45843319cdc5ce506516eb49bf7a,996865bb912f3bc45898a370a13aadb315014b55,17471a5fda722a9e423f1a0d3f0d267ea009d41c,51f6dcf6b89b93f4075ba92c400b075631a6cc93,b10b3e2cb320a8c211fda94c4567299d37de7776",
  112. },
  113. wantPath: "../test_data/test_local_repo_two_leaks_commit_range.json",
  114. },
  115. {
  116. description: "test local repo two leaks file list commits",
  117. opts: options.Options{
  118. Path: "../test_data/test_repos/test_repo_2",
  119. Report: "../test_data/test_local_repo_two_leaks_file_commit_range.json.got",
  120. ReportFormat: "json",
  121. CommitsFile: "../test_data/test_options/test_local_repo_commits.txt",
  122. },
  123. wantPath: "../test_data/test_local_repo_two_leaks_file_commit_range.json",
  124. },
  125. {
  126. description: "test local repo two leaks globally allowlisted",
  127. opts: options.Options{
  128. Path: "../test_data/test_repos/test_repo_2",
  129. ConfigPath: "../test_data/test_configs/aws_key_global_allowlist_file.toml",
  130. ReportFormat: "json",
  131. },
  132. wantEmpty: true,
  133. },
  134. {
  135. description: "test local repo two leaks allowlisted",
  136. opts: options.Options{
  137. Path: "../test_data/test_repos/test_repo_2",
  138. ConfigPath: "../test_data/test_configs/aws_key_allowlist_files.toml",
  139. ReportFormat: "json",
  140. },
  141. wantEmpty: true,
  142. },
  143. {
  144. description: "test local repo three leaks dev branch with reportGroup set",
  145. opts: options.Options{
  146. Path: "../test_data/test_repos/test_repo_3",
  147. Report: "../test_data/test_local_repo_three_leaks_with_report_groups.json.got",
  148. ConfigPath: "../test_data/test_configs/aws_key_with_report_groups.toml",
  149. Branch: "dev",
  150. ReportFormat: "json",
  151. },
  152. wantPath: "../test_data/test_local_repo_three_leaks_with_report_groups.json",
  153. },
  154. {
  155. description: "test local repo three leaks dev branch",
  156. opts: options.Options{
  157. Path: "../test_data/test_repos/test_repo_3",
  158. Report: "../test_data/test_local_repo_three_leaks.json.got",
  159. ConfigPath: "../test_data/test_configs/aws_key.toml",
  160. Branch: "dev",
  161. ReportFormat: "json",
  162. },
  163. wantPath: "../test_data/test_local_repo_three_leaks.json",
  164. },
  165. {
  166. description: "test local repo branch does not exist",
  167. opts: options.Options{
  168. Path: "../test_data/test_repos/test_repo_3",
  169. Branch: "nobranch",
  170. ReportFormat: "json",
  171. },
  172. wantScanErr: fmt.Errorf("could not find branch nobranch"),
  173. },
  174. {
  175. description: "test local repo one aws leak single Commit",
  176. opts: options.Options{
  177. Path: "../test_data/test_repos/test_repo_1",
  178. Report: "../test_data/test_local_repo_one_aws_leak_commit.json.got",
  179. Commit: "6557c92612d3b35979bd426d429255b3bf9fab74",
  180. ReportFormat: "json",
  181. },
  182. wantPath: "../test_data/test_local_repo_one_aws_leak_commit.json",
  183. },
  184. {
  185. description: "test local repo one aws leak AND leak on python files",
  186. opts: options.Options{
  187. Path: "../test_data/test_repos/test_repo_1",
  188. Report: "../test_data/test_local_repo_one_aws_leak_and_file_leak.json.got",
  189. ConfigPath: "../test_data/test_configs/aws_key_file_regex.toml",
  190. ReportFormat: "json",
  191. },
  192. wantPath: "../test_data/test_local_repo_one_aws_leak_and_file_leak.json",
  193. },
  194. {
  195. description: "test owner path",
  196. opts: options.Options{
  197. Path: "../test_data/test_repos/",
  198. Report: "../test_data/test_local_owner_aws_leak.json.got",
  199. ReportFormat: "json",
  200. },
  201. wantPath: "../test_data/test_local_owner_aws_leak.json",
  202. },
  203. {
  204. description: "test owner path allowlist repo",
  205. opts: options.Options{
  206. Path: "../test_data/test_repos/",
  207. Report: "../test_data/test_local_owner_aws_leak_allowlist_repo.json.got",
  208. ReportFormat: "json",
  209. ConfigPath: "../test_data/test_configs/aws_key_local_owner_allowlist_repo.toml",
  210. },
  211. wantPath: "../test_data/test_local_owner_aws_leak_allowlist_repo.json",
  212. },
  213. {
  214. description: "test entropy and regex",
  215. opts: options.Options{
  216. Path: "../test_data/test_repos/test_repo_1",
  217. Report: "../test_data/test_regex_entropy.json.got",
  218. ConfigPath: "../test_data/test_configs/regex_entropy.toml",
  219. ReportFormat: "json",
  220. },
  221. wantPath: "../test_data/test_regex_entropy.json",
  222. },
  223. {
  224. description: "test local repo four entropy alternative config",
  225. opts: options.Options{
  226. Path: "../test_data/test_repos/test_repo_4",
  227. Report: "../test_data/test_local_repo_four_alt_config_entropy.json.got",
  228. RepoConfigPath: "gitleaks.toml",
  229. ReportFormat: "json",
  230. },
  231. wantPath: "../test_data/test_local_repo_four_alt_config_entropy.json",
  232. },
  233. {
  234. description: "test local repo four entropy alternative config",
  235. opts: options.Options{
  236. Path: "../test_data/test_repos/test_repo_1",
  237. Report: "../test_data/test_regex_allowlist.json.got",
  238. ConfigPath: "../test_data/test_configs/aws_key_aws_allowlisted.toml",
  239. ReportFormat: "json",
  240. },
  241. wantEmpty: true,
  242. },
  243. {
  244. description: "test owner path depth=2",
  245. opts: options.Options{
  246. Path: "../test_data/test_repos/",
  247. Report: "../test_data/test_local_owner_aws_leak_depth_2.json.got",
  248. ReportFormat: "json",
  249. Depth: 2,
  250. },
  251. wantPath: "../test_data/test_local_owner_aws_leak_depth_2.json",
  252. },
  253. {
  254. description: "test local repo five files at Commit",
  255. opts: options.Options{
  256. Path: "../test_data/test_repos/test_repo_5",
  257. Report: "../test_data/test_local_repo_five_files_at_commit.json.got",
  258. FilesAtCommit: "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
  259. ReportFormat: "json",
  260. },
  261. wantPath: "../test_data/test_local_repo_five_files_at_commit.json",
  262. },
  263. {
  264. description: "test local repo five files at latest Commit",
  265. opts: options.Options{
  266. Path: "../test_data/test_repos/test_repo_5",
  267. Report: "../test_data/test_local_repo_five_files_at_latest_commit.json.got",
  268. FilesAtCommit: "latest",
  269. ReportFormat: "json",
  270. },
  271. wantPath: "../test_data/test_local_repo_five_files_at_commit.json",
  272. },
  273. {
  274. description: "test local repo five at Commit",
  275. opts: options.Options{
  276. Path: "../test_data/test_repos/test_repo_5",
  277. Report: "../test_data/test_local_repo_five_commit.json.got",
  278. Commit: "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
  279. ReportFormat: "json",
  280. ConfigPath: "../test_data/test_configs/generic.toml",
  281. },
  282. wantPath: "../test_data/test_local_repo_five_commit.json",
  283. },
  284. {
  285. description: "test local repo five at latest Commit",
  286. opts: options.Options{
  287. Path: "../test_data/test_repos/test_repo_5",
  288. Report: "../test_data/test_local_repo_five_at_latest_commit.json.got",
  289. Commit: "latest",
  290. ReportFormat: "json",
  291. ConfigPath: "../test_data/test_configs/generic.toml",
  292. },
  293. wantPath: "../test_data/test_local_repo_five_at_latest_commit.json",
  294. },
  295. {
  296. description: "test local repo six filename",
  297. opts: options.Options{
  298. Path: "../test_data/test_repos/test_repo_6",
  299. Report: "../test_data/test_local_repo_six_filename.json.got",
  300. ConfigPath: "../test_data/test_configs/regex_filename.toml",
  301. ReportFormat: "json",
  302. },
  303. wantPath: "../test_data/test_local_repo_six_filename.json",
  304. },
  305. {
  306. description: "test local repo six filepath",
  307. opts: options.Options{
  308. Path: "../test_data/test_repos/test_repo_6",
  309. Report: "../test_data/test_local_repo_six_filepath.json.got",
  310. ConfigPath: "../test_data/test_configs/regex_filepath.toml",
  311. ReportFormat: "json",
  312. },
  313. wantPath: "../test_data/test_local_repo_six_filepath.json",
  314. },
  315. {
  316. description: "test local repo six filename and filepath",
  317. opts: options.Options{
  318. Path: "../test_data/test_repos/test_repo_6",
  319. Report: "../test_data/test_local_repo_six_filepath_filename.json.got",
  320. ConfigPath: "../test_data/test_configs/regex_filepath_filename.toml",
  321. ReportFormat: "json",
  322. },
  323. wantPath: "../test_data/test_local_repo_six_filepath_filename.json",
  324. },
  325. {
  326. description: "test local repo six path globally allowlisted",
  327. opts: options.Options{
  328. Path: "../test_data/test_repos/test_repo_6",
  329. Report: "../test_data/test_local_repo_six_path_globally_allowlisted.json.got",
  330. ConfigPath: "../test_data/test_configs/aws_key_global_allowlist_path.toml",
  331. ReportFormat: "json",
  332. },
  333. wantPath: "../test_data/test_local_repo_six_path_globally_allowlisted.json",
  334. },
  335. {
  336. description: "test local repo six leaks since date",
  337. opts: options.Options{
  338. Path: "../test_data/test_repos/test_repo_6",
  339. Report: "../test_data/test_local_repo_six_leaks_since_date.json.got",
  340. ReportFormat: "json",
  341. CommitSince: "2019-10-25",
  342. },
  343. wantPath: "../test_data/test_local_repo_six_leaks_since_date.json",
  344. },
  345. {
  346. description: "test local repo two leaks until date",
  347. opts: options.Options{
  348. Path: "../test_data/test_repos/test_repo_6",
  349. Report: "../test_data/test_local_repo_six_leaks_until_date.json.got",
  350. ReportFormat: "json",
  351. CommitUntil: "2019-10-25",
  352. },
  353. wantPath: "../test_data/test_local_repo_six_leaks_until_date.json",
  354. },
  355. {
  356. description: "test local repo four leaks timerange Commit",
  357. opts: options.Options{
  358. Path: "../test_data/test_repos/test_repo_4",
  359. Report: "../test_data/test_local_repo_four_leaks_commit_timerange.json.got",
  360. ReportFormat: "json",
  361. CommitSince: "2019-10-25T13:01:27-0400",
  362. CommitUntil: "2019-10-25T13:12:32-0400",
  363. },
  364. wantPath: "../test_data/test_local_repo_four_leaks_commit_timerange.json",
  365. },
  366. {
  367. description: "test local repo two allowlist Commit config",
  368. opts: options.Options{
  369. Path: "../test_data/test_repos/test_repo_2",
  370. Report: "../test_data/test_local_repo_two_allowlist_commits.json.got",
  371. ConfigPath: "../test_data/test_configs/allowlist_commit.toml",
  372. ReportFormat: "json",
  373. },
  374. wantPath: "../test_data/test_local_repo_two_allowlist_commits.json",
  375. },
  376. {
  377. description: "test local repo eight (merges)",
  378. opts: options.Options{
  379. Path: "../test_data/test_repos/test_repo_8",
  380. Report: "../test_data/test_local_repo_eight.json.got",
  381. ReportFormat: "json",
  382. },
  383. wantPath: "../test_data/test_local_repo_eight.json",
  384. },
  385. {
  386. description: "test local repo nine",
  387. opts: options.Options{
  388. Path: "../test_data/test_repos/test_repo_9",
  389. Report: "../test_data/test_local_repo_nine_aws_leak.json.got",
  390. ConfigPath: "../test_data/test_configs/large_with_global_allowlist_regex.toml",
  391. ReportFormat: "json",
  392. },
  393. wantPath: "../test_data/test_local_repo_nine_aws_leak.json",
  394. },
  395. {
  396. description: "test dir one no git",
  397. opts: options.Options{
  398. Path: "../test_data/test_repos/test_dir_1",
  399. Report: "../test_data/test_dir1_aws_leak.json.got",
  400. ReportFormat: "json",
  401. NoGit: true,
  402. },
  403. wantPath: "../test_data/test_dir1_aws_leak.json",
  404. },
  405. {
  406. description: "test file with leak no git",
  407. opts: options.Options{
  408. Path: "../test_data/test_repos/test_dir_1/server.test.py",
  409. Report: "../test_data/test_file1_aws_leak.json.got",
  410. ReportFormat: "json",
  411. NoGit: true,
  412. },
  413. wantPath: "../test_data/test_file1_aws_leak.json",
  414. },
  415. {
  416. description: "test only md files no git",
  417. opts: options.Options{
  418. Path: "../test_data/test_repos/",
  419. Report: "../test_data/test_only_files_no_git.json.got",
  420. ReportFormat: "json",
  421. ConfigPath: "../test_data/test_configs/onlyFiles.toml",
  422. NoGit: true,
  423. },
  424. wantPath: "../test_data/test_only_files_no_git.json",
  425. },
  426. }
  427. for _, test := range tests {
  428. fmt.Println(test.description)
  429. cfg, err := config.NewConfig(test.opts)
  430. if err != nil {
  431. t.Error(err)
  432. }
  433. scanner, err := NewScanner(test.opts, cfg)
  434. if test.wantErr != nil {
  435. if err == nil {
  436. t.Fatalf("did not receive wantErr: %v", test.wantErr)
  437. }
  438. if err.Error() != test.wantErr.Error() {
  439. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  440. }
  441. continue
  442. }
  443. if err != nil {
  444. t.Fatal(err)
  445. }
  446. scannerReport, err := scanner.Scan()
  447. if test.wantScanErr != nil {
  448. if err == nil {
  449. t.Fatalf("did not receive wantErr: %v", test.wantScanErr)
  450. }
  451. if err.Error() != test.wantScanErr.Error() {
  452. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  453. }
  454. continue
  455. }
  456. if err != nil {
  457. t.Fatal(err)
  458. }
  459. err = WriteReport(scannerReport, test.opts, cfg)
  460. if err != nil {
  461. t.Error(err)
  462. }
  463. if test.wantEmpty {
  464. if len(scannerReport.Leaks) != 0 {
  465. t.Errorf("wanted no leaks but got some instead: %+v", scannerReport.Leaks)
  466. }
  467. continue
  468. }
  469. if test.wantPath != "" {
  470. err := fileCheck(test.wantPath, test.opts.Report)
  471. if err != nil {
  472. t.Error(err)
  473. }
  474. }
  475. }
  476. }
  477. //
  478. func TestScanUncommited(t *testing.T) {
  479. moveDotGit("dotGit", ".git")
  480. defer moveDotGit(".git", "dotGit")
  481. tests := []struct {
  482. description string
  483. opts options.Options
  484. wantPath string
  485. wantErr error
  486. wantScanErr error
  487. emptyRepo bool
  488. wantEmpty bool
  489. fileToChange string
  490. addition string
  491. }{
  492. {
  493. description: "test scan local one leak",
  494. opts: options.Options{
  495. Path: "../test_data/test_repos/test_repo_1",
  496. Report: "../test_data/test_local_repo_one_aws_leak_uncommitted.json.got",
  497. Unstaged: true,
  498. ReportFormat: "json",
  499. },
  500. wantPath: "../test_data/test_local_repo_one_aws_leak_uncommitted.json",
  501. fileToChange: "server.test.py",
  502. addition: " aws_access_key_id='AKIAIO5FODNN7DXAMPLE'\n\n",
  503. },
  504. {
  505. description: "test scan local no leak",
  506. opts: options.Options{
  507. Path: "../test_data/test_repos/test_repo_1",
  508. Unstaged: true,
  509. ReportFormat: "json",
  510. },
  511. wantEmpty: true,
  512. fileToChange: "server.test.py",
  513. addition: "nothing bad",
  514. },
  515. {
  516. description: "test scan repo with no commits",
  517. opts: options.Options{
  518. Path: "../test_data/test_repos/test_repo_7",
  519. Report: "../test_data/test_local_repo_seven_aws_leak_uncommitted.json.got",
  520. Unstaged: true,
  521. ReportFormat: "json",
  522. },
  523. wantPath: "../test_data/test_local_repo_seven_aws_leak_uncommitted.json",
  524. },
  525. }
  526. for _, test := range tests {
  527. var (
  528. old []byte
  529. err error
  530. )
  531. fmt.Println(test.description)
  532. if test.fileToChange != "" {
  533. old, err = ioutil.ReadFile(fmt.Sprintf("%s/%s", test.opts.Path, test.fileToChange))
  534. if err != nil {
  535. t.Error(err)
  536. }
  537. altered, err := os.OpenFile(fmt.Sprintf("%s/%s", test.opts.Path, test.fileToChange),
  538. os.O_WRONLY|os.O_APPEND, 0644)
  539. if err != nil {
  540. t.Error(err)
  541. }
  542. _, err = altered.WriteString(test.addition)
  543. if err != nil {
  544. t.Error(err)
  545. }
  546. }
  547. cfg, err := config.NewConfig(test.opts)
  548. if err != nil {
  549. t.Error(err)
  550. }
  551. scanner, err := NewScanner(test.opts, cfg)
  552. if test.wantErr != nil {
  553. if err == nil {
  554. t.Fatalf("did not receive wantErr: %v", test.wantErr)
  555. }
  556. if err.Error() != test.wantErr.Error() {
  557. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  558. }
  559. continue
  560. }
  561. if err != nil {
  562. t.Fatal(err)
  563. }
  564. scannerReport, err := scanner.Scan()
  565. if test.wantScanErr != nil {
  566. if err == nil {
  567. t.Fatalf("did not receive wantErr: %v", test.wantScanErr)
  568. }
  569. if err.Error() != test.wantScanErr.Error() {
  570. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  571. }
  572. continue
  573. }
  574. if err != nil {
  575. t.Fatal(err)
  576. }
  577. err = WriteReport(scannerReport, test.opts, cfg)
  578. if err != nil {
  579. t.Error(err)
  580. }
  581. if test.fileToChange != "" {
  582. err = ioutil.WriteFile(fmt.Sprintf("%s/%s", test.opts.Path, test.fileToChange), old, 0)
  583. if err != nil {
  584. t.Error(err)
  585. }
  586. }
  587. if test.wantEmpty {
  588. continue
  589. }
  590. if test.wantPath != "" {
  591. err := fileCheck(test.wantPath, test.opts.Report)
  592. if err != nil {
  593. t.Error(err)
  594. }
  595. }
  596. }
  597. }
  598. func fileCheck(wantPath, gotPath string) error {
  599. var (
  600. gotLeaks []Leak
  601. wantLeaks []Leak
  602. )
  603. want, err := ioutil.ReadFile(wantPath)
  604. if err != nil {
  605. return err
  606. }
  607. got, err := ioutil.ReadFile(gotPath)
  608. if err != nil {
  609. return err
  610. }
  611. err = json.Unmarshal(got, &gotLeaks)
  612. if err != nil {
  613. return err
  614. }
  615. err = json.Unmarshal(want, &wantLeaks)
  616. if err != nil {
  617. return err
  618. }
  619. sort.Slice(gotLeaks, func(i, j int) bool {
  620. return (gotLeaks)[i].Offender+(gotLeaks)[i].File < (gotLeaks)[j].Offender+(gotLeaks)[j].File
  621. })
  622. sort.Slice(wantLeaks, func(i, j int) bool {
  623. return (wantLeaks)[i].Offender+(wantLeaks)[i].File < (wantLeaks)[j].Offender+(wantLeaks)[j].File
  624. })
  625. if !reflect.DeepEqual(gotLeaks, wantLeaks) {
  626. dmp := diffmatchpatch.New()
  627. diffs := dmp.DiffMain(string(want), string(got), false)
  628. return fmt.Errorf("%s does not equal %s: %s", wantPath, gotPath, dmp.DiffPrettyText(diffs))
  629. }
  630. if err := os.Remove(gotPath); err != nil {
  631. return err
  632. }
  633. return nil
  634. }
  635. func moveDotGit(from, to string) error {
  636. repoDirs, err := ioutil.ReadDir("../test_data/test_repos")
  637. if err != nil {
  638. return err
  639. }
  640. for _, dir := range repoDirs {
  641. if !dir.IsDir() {
  642. continue
  643. }
  644. _, err := os.Stat(fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), from))
  645. if os.IsNotExist(err) {
  646. continue
  647. }
  648. err = os.Rename(fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), from),
  649. fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), to))
  650. if err != nil {
  651. return err
  652. }
  653. }
  654. return nil
  655. }