scan_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  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",
  442. opts: options.Options{
  443. Path: "../test_data/test_repos/test_repo_10",
  444. Report: "../test_data/test_allow_list_file.json.got",
  445. ReportFormat: "json",
  446. ConfigPath: "../test_data/test_configs/allowlist_files.toml",
  447. },
  448. wantPath: "../test_data/test_allow_list_file.json",
  449. },
  450. {
  451. description: "test allowlist files no-git",
  452. opts: options.Options{
  453. Path: "../test_data/test_repos/test_repo_10",
  454. Report: "../test_data/test_allow_list_file_no_git.json.got",
  455. ReportFormat: "json",
  456. ConfigPath: "../test_data/test_configs/allowlist_files.toml",
  457. NoGit: true,
  458. },
  459. wantPath: "../test_data/test_allow_list_file_no_git.json",
  460. },
  461. {
  462. description: "test allowlist docx no-git",
  463. opts: options.Options{
  464. Path: "../test_data/test_repos/test_repo_10",
  465. Report: "../test_data/test_allow_list_docx_no_git.json.got",
  466. ReportFormat: "json",
  467. ConfigPath: "../test_data/test_configs/allowlist_docx.toml",
  468. NoGit: true,
  469. },
  470. wantPath: "../test_data/test_allow_list_docx_no_git.json",
  471. },
  472. {
  473. description: "test append repo config",
  474. opts: options.Options{
  475. Path: "../test_data/test_repos/test_repo_10",
  476. Report: "../test_data/test_append_repo.json.got",
  477. ReportFormat: "json",
  478. ConfigPath: "../test_data/test_configs/nozips.toml",
  479. RepoConfigPath: ".gitleaks.toml",
  480. AppendRepoConfig: true,
  481. },
  482. wantPath: "../test_data/test_append_repo.json",
  483. },
  484. {
  485. description: "test additional config",
  486. opts: options.Options{
  487. Path: "../test_data/test_repos/test_repo_10",
  488. Report: "../test_data/test_additional_config.json.got",
  489. ReportFormat: "json",
  490. ConfigPath: "../test_data/test_configs/nozips.toml",
  491. AdditionalConfig: "../test_data/test_repos/test_repo_10/.gitleaks.toml",
  492. },
  493. wantPath: "../test_data/test_additional_config.json",
  494. },
  495. {
  496. description: "test append repo config with additional config",
  497. opts: options.Options{
  498. Path: "../test_data/test_repos/test_repo_10",
  499. Report: "../test_data/test_append_repo_additional_config.json.got",
  500. ReportFormat: "json",
  501. ConfigPath: "../test_data/test_configs/nozips.toml",
  502. RepoConfigPath: ".gitleaks.toml",
  503. AppendRepoConfig: true,
  504. AdditionalConfig: "../test_data/test_configs/allowlist_bad_docx_10.toml",
  505. },
  506. wantEmpty: true,
  507. },
  508. {
  509. description: "test append repo config with additional config",
  510. opts: options.Options{
  511. Path: "../test_data/test_repos/test_repo_10",
  512. Report: "../test_data/test_append_repo_additional_config.json.got",
  513. ReportFormat: "json",
  514. ConfigPath: "../test_data/test_configs/nozips.toml",
  515. RepoConfigPath: ".gitleaks.toml",
  516. AppendRepoConfig: true,
  517. AdditionalConfig: "../test_data/test_configs/allowlist_bad_docx_10.toml",
  518. },
  519. wantEmpty: true,
  520. },
  521. {
  522. description: "test file with no leak due to additional config no git",
  523. opts: options.Options{
  524. Path: "../test_data/test_repos/test_dir_1",
  525. Report: "../test_data/fail.json.got",
  526. ReportFormat: "json",
  527. NoGit: false,
  528. AdditionalConfig: "../test_data/test_configs/allowlist_allow_all_repo_1.toml",
  529. },
  530. wantEmpty: true,
  531. },
  532. }
  533. for _, test := range tests {
  534. fmt.Println(test.description)
  535. cfg, err := config.NewConfig(test.opts)
  536. if err != nil {
  537. t.Error(err)
  538. }
  539. scanner, err := NewScanner(test.opts, cfg)
  540. if test.wantErr != nil {
  541. if err == nil {
  542. t.Fatalf("did not receive wantErr: %v", test.wantErr)
  543. }
  544. if err.Error() != test.wantErr.Error() {
  545. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  546. }
  547. continue
  548. }
  549. if err != nil {
  550. t.Fatal(err)
  551. }
  552. scannerReport, err := scanner.Scan()
  553. if test.wantScanErr != nil {
  554. if err == nil {
  555. t.Fatalf("did not receive wantErr: %v", test.wantScanErr)
  556. }
  557. if err.Error() != test.wantScanErr.Error() {
  558. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  559. }
  560. continue
  561. }
  562. if err != nil {
  563. t.Fatal(err)
  564. }
  565. err = WriteReport(scannerReport, test.opts, cfg)
  566. if err != nil {
  567. t.Error(err)
  568. }
  569. if test.wantEmpty {
  570. if len(scannerReport.Leaks) != 0 {
  571. t.Errorf("wanted no leaks but got some instead: %+v", scannerReport.Leaks)
  572. }
  573. continue
  574. }
  575. if test.wantPath != "" {
  576. err := fileCheck(test.wantPath, test.opts.Report)
  577. if err != nil {
  578. t.Error(err)
  579. }
  580. }
  581. }
  582. }
  583. //
  584. func TestScanUncommited(t *testing.T) {
  585. moveDotGit("dotGit", ".git")
  586. defer moveDotGit(".git", "dotGit")
  587. tests := []struct {
  588. description string
  589. opts options.Options
  590. wantPath string
  591. wantErr error
  592. wantScanErr error
  593. emptyRepo bool
  594. wantEmpty bool
  595. fileToChange string
  596. addition string
  597. }{
  598. {
  599. description: "test scan local one leak",
  600. opts: options.Options{
  601. Path: "../test_data/test_repos/test_repo_1",
  602. Report: "../test_data/test_local_repo_one_aws_leak_uncommitted.json.got",
  603. Unstaged: true,
  604. ReportFormat: "json",
  605. },
  606. wantPath: "../test_data/test_local_repo_one_aws_leak_uncommitted.json",
  607. fileToChange: "server.test.py",
  608. addition: " aws_access_key_id='AKIAIO5FODNN7DXAMPLE'\n\n",
  609. },
  610. {
  611. description: "test scan local no leak",
  612. opts: options.Options{
  613. Path: "../test_data/test_repos/test_repo_1",
  614. Unstaged: true,
  615. ReportFormat: "json",
  616. },
  617. wantEmpty: true,
  618. fileToChange: "server.test.py",
  619. addition: "nothing bad",
  620. },
  621. {
  622. description: "test scan repo with no commits",
  623. opts: options.Options{
  624. Path: "../test_data/test_repos/test_repo_7",
  625. Report: "../test_data/test_local_repo_seven_aws_leak_uncommitted.json.got",
  626. Unstaged: true,
  627. ReportFormat: "json",
  628. },
  629. wantPath: "../test_data/test_local_repo_seven_aws_leak_uncommitted.json",
  630. },
  631. }
  632. for _, test := range tests {
  633. var (
  634. old []byte
  635. err error
  636. )
  637. fmt.Println(test.description)
  638. if test.fileToChange != "" {
  639. old, err = ioutil.ReadFile(fmt.Sprintf("%s/%s", test.opts.Path, test.fileToChange))
  640. if err != nil {
  641. t.Error(err)
  642. }
  643. altered, err := os.OpenFile(fmt.Sprintf("%s/%s", test.opts.Path, test.fileToChange),
  644. os.O_WRONLY|os.O_APPEND, 0644)
  645. if err != nil {
  646. t.Error(err)
  647. }
  648. _, err = altered.WriteString(test.addition)
  649. if err != nil {
  650. t.Error(err)
  651. }
  652. }
  653. cfg, err := config.NewConfig(test.opts)
  654. if err != nil {
  655. t.Error(err)
  656. }
  657. scanner, err := NewScanner(test.opts, cfg)
  658. if test.wantErr != nil {
  659. if err == nil {
  660. t.Fatalf("did not receive wantErr: %v", test.wantErr)
  661. }
  662. if err.Error() != test.wantErr.Error() {
  663. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  664. }
  665. continue
  666. }
  667. if err != nil {
  668. t.Fatal(err)
  669. }
  670. scannerReport, err := scanner.Scan()
  671. if test.wantScanErr != nil {
  672. if err == nil {
  673. t.Fatalf("did not receive wantErr: %v", test.wantScanErr)
  674. }
  675. if err.Error() != test.wantScanErr.Error() {
  676. t.Fatalf("wantErr does not equal err received: %v", err.Error())
  677. }
  678. continue
  679. }
  680. if err != nil {
  681. t.Fatal(err)
  682. }
  683. err = WriteReport(scannerReport, test.opts, cfg)
  684. if err != nil {
  685. t.Error(err)
  686. }
  687. if test.fileToChange != "" {
  688. err = ioutil.WriteFile(fmt.Sprintf("%s/%s", test.opts.Path, test.fileToChange), old, 0)
  689. if err != nil {
  690. t.Error(err)
  691. }
  692. }
  693. if test.wantEmpty {
  694. continue
  695. }
  696. if test.wantPath != "" {
  697. err := fileCheck(test.wantPath, test.opts.Report)
  698. if err != nil {
  699. t.Error(err)
  700. }
  701. }
  702. }
  703. }
  704. func fileCheck(wantPath, gotPath string) error {
  705. var (
  706. gotLeaks []Leak
  707. wantLeaks []Leak
  708. )
  709. want, err := ioutil.ReadFile(wantPath)
  710. if err != nil {
  711. return err
  712. }
  713. got, err := ioutil.ReadFile(gotPath)
  714. if err != nil {
  715. return err
  716. }
  717. err = json.Unmarshal(got, &gotLeaks)
  718. if err != nil {
  719. return err
  720. }
  721. err = json.Unmarshal(want, &wantLeaks)
  722. if err != nil {
  723. return err
  724. }
  725. if len(wantLeaks) != len(gotLeaks) {
  726. return fmt.Errorf("got %d leaks, want %d leaks", len(gotLeaks), len(wantLeaks))
  727. }
  728. for _, wantLeak := range wantLeaks {
  729. found := false
  730. for _, gotLeak := range gotLeaks {
  731. if same(gotLeak, wantLeak) {
  732. found = true
  733. }
  734. }
  735. if !found {
  736. return fmt.Errorf("unable to find %+v in got leaks", wantLeak)
  737. }
  738. }
  739. if err := os.Remove(gotPath); err != nil {
  740. return err
  741. }
  742. return nil
  743. }
  744. func same(l1, l2 Leak) bool {
  745. if l1.Commit != l2.Commit {
  746. return false
  747. }
  748. if l1.Offender != l2.Offender {
  749. return false
  750. }
  751. if l1.Line != l2.Line {
  752. return false
  753. }
  754. if l1.Tags != l2.Tags {
  755. return false
  756. }
  757. if l1.LineNumber != l2.LineNumber {
  758. return false
  759. }
  760. if l1.Author != l2.Author {
  761. return false
  762. }
  763. if l1.LeakURL != l2.LeakURL {
  764. return false
  765. }
  766. if l1.RepoURL != l2.RepoURL {
  767. return false
  768. }
  769. if l1.Repo != l2.Repo {
  770. return false
  771. }
  772. return true
  773. }
  774. func moveDotGit(from, to string) error {
  775. repoDirs, err := ioutil.ReadDir("../test_data/test_repos")
  776. if err != nil {
  777. return err
  778. }
  779. for _, dir := range repoDirs {
  780. if to == ".git" {
  781. _, err := os.Stat(fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), "dotGit"))
  782. if os.IsNotExist(err) {
  783. // dont want to delete the only copy of .git accidentally
  784. continue
  785. }
  786. os.RemoveAll(fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), ".git"))
  787. }
  788. if !dir.IsDir() {
  789. continue
  790. }
  791. _, err := os.Stat(fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), from))
  792. if os.IsNotExist(err) {
  793. continue
  794. }
  795. err = os.Rename(fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), from),
  796. fmt.Sprintf("%s/%s/%s", testRepoBase, dir.Name(), to))
  797. if err != nil {
  798. return err
  799. }
  800. // fmt.Println("RENAMED")
  801. }
  802. return nil
  803. }