scan_test.go 24 KB

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