shadowbq-threatinator 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +66 -0
  3. data/CONTRIBUTING.md +119 -0
  4. data/Gemfile +38 -0
  5. data/LICENSE +165 -0
  6. data/README.md +101 -0
  7. data/Rakefile +47 -0
  8. data/VERSION +1 -0
  9. data/bin/threatinator +5 -0
  10. data/bin/threatinator_loader +21 -0
  11. data/feeds/ET_block-ip_reputation.feed +27 -0
  12. data/feeds/ET_compromised-ip_reputation.feed +20 -0
  13. data/feeds/ET_openbadlist-ip_reputation.feed +36 -0
  14. data/feeds/alienvault-ip_reputation.feed +39 -0
  15. data/feeds/arbor_fastflux-domain_reputation.feed +19 -0
  16. data/feeds/arbor_ssh-ip_reputation.feed +24 -0
  17. data/feeds/autoshun_shunlist.feed +17 -0
  18. data/feeds/bambenek_c2_masterlist-domain_reputation.feed +16 -0
  19. data/feeds/bambenek_c2_masterlist-ip_reputation.feed +16 -0
  20. data/feeds/bambenek_dga_feed-domain_reputation.feed +16 -0
  21. data/feeds/berkeley-ip_reputation.feed +25 -0
  22. data/feeds/bitcash_cz_blacklist.feed +22 -0
  23. data/feeds/blocklist_de_apache-ip_reputation.feed +26 -0
  24. data/feeds/blocklist_de_bots-ip_reputation.feed +26 -0
  25. data/feeds/blocklist_de_ftp-ip_reputation.feed +25 -0
  26. data/feeds/blocklist_de_imap-ip_reputation.feed +25 -0
  27. data/feeds/blocklist_de_pop3-ip_reputation.feed +26 -0
  28. data/feeds/blocklist_de_proftpd-ip_reputation.feed +26 -0
  29. data/feeds/blocklist_de_sip-ip_reputation.feed +25 -0
  30. data/feeds/blocklist_de_ssh-ip_reputation.feed +25 -0
  31. data/feeds/blocklist_de_strongips-ip_reputation.feed +25 -0
  32. data/feeds/botscout-ip_reputation.feed +25 -0
  33. data/feeds/cert_mxpoison-ip_reputation.feed +22 -0
  34. data/feeds/chaosreigns-ip_reputation.feed +37 -0
  35. data/feeds/ciarmy-ip_reputation.feed +20 -0
  36. data/feeds/cruzit-ip_reputation.feed +30 -0
  37. data/feeds/cydef_torexit-ip_reputation.feed +25 -0
  38. data/feeds/dan_me_uk_torlist-ip_reputation.feed +25 -0
  39. data/feeds/danger_bruteforce-ip_reputation.feed +24 -0
  40. data/feeds/dshield_attackers-top1000.feed +34 -0
  41. data/feeds/falconcrest-ip_reputation.feed +19 -0
  42. data/feeds/feodo-domain_reputation.feed +19 -0
  43. data/feeds/feodo-ip_reputation.feed +20 -0
  44. data/feeds/h3x_asprox.feed +18 -0
  45. data/feeds/hosts-file_hphostspartial-domain_reputation.feed +19 -0
  46. data/feeds/infiltrated-ip_reputation.feed +26 -0
  47. data/feeds/infiltrated_vabl-ip_reputation.feed +30 -0
  48. data/feeds/isc_suspicious_high-domain_reputation.feed +26 -0
  49. data/feeds/isc_suspicious_low-domain_reputation.feed +26 -0
  50. data/feeds/isc_suspicious_medium-domain_reputation.feed +26 -0
  51. data/feeds/malc0de-domain_reputation.feed +24 -0
  52. data/feeds/malc0de-ip_reputation.feed +26 -0
  53. data/feeds/malwaredomainlist-url_reputation.feed +18 -0
  54. data/feeds/malwaredomains-domain_reputation.feed +29 -0
  55. data/feeds/malwaredomains_dyndns-domain_reputation.feed +29 -0
  56. data/feeds/malwaredomains_justdomains-domain_reputation.feed +20 -0
  57. data/feeds/mirc-domain_reputation.feed +30 -0
  58. data/feeds/multiproxy-ip_reputation.feed +22 -0
  59. data/feeds/nothink_irc-ip_reputation.feed +23 -0
  60. data/feeds/nothink_ssh-ip_reputation.feed +21 -0
  61. data/feeds/openbl-ip_reputation.feed +21 -0
  62. data/feeds/openphish-url_reputation.feed +24 -0
  63. data/feeds/packetmail_perimeterbad-ip_reputation.feed +28 -0
  64. data/feeds/palevo-domain_reputation.feed +22 -0
  65. data/feeds/palevo-ip_reputation.feed +23 -0
  66. data/feeds/phishtank.feed +22 -0
  67. data/feeds/sigmaproject_atma.feed +27 -0
  68. data/feeds/sigmaproject_spyware.feed +28 -0
  69. data/feeds/sigmaproject_webexploit.feed +26 -0
  70. data/feeds/snort_bpf-ip_reputation.feed +19 -0
  71. data/feeds/spyeye-domain_reputation.feed +18 -0
  72. data/feeds/spyeye-ip_reputation.feed +19 -0
  73. data/feeds/steeman-ip_reputation.feed +20 -0
  74. data/feeds/t-arend-de_ssh-ip_reputation.feed +20 -0
  75. data/feeds/the_haleys_ssh-ip_reputation.feed +20 -0
  76. data/feeds/trustedsec-ip_reputation.feed +18 -0
  77. data/feeds/virbl-ip_reputation.feed +25 -0
  78. data/feeds/vxvault-url_reputation.feed +23 -0
  79. data/feeds/yourcmc_ssh-ip_reputation.feed +20 -0
  80. data/feeds/yoyo_adservers-domain_reputation.feed +17 -0
  81. data/feeds/zeus-domain_reputation.feed +19 -0
  82. data/feeds/zeus-ip_reputation.feed +21 -0
  83. data/lib/threatinator/action.rb +14 -0
  84. data/lib/threatinator/actions/list/action.rb +97 -0
  85. data/lib/threatinator/actions/list/config.rb +12 -0
  86. data/lib/threatinator/actions/list.rb +2 -0
  87. data/lib/threatinator/actions/run/action.rb +57 -0
  88. data/lib/threatinator/actions/run/config.rb +32 -0
  89. data/lib/threatinator/actions/run/coverage_observer.rb +59 -0
  90. data/lib/threatinator/actions/run/output_config.rb +59 -0
  91. data/lib/threatinator/actions/run/status_observer.rb +37 -0
  92. data/lib/threatinator/actions/run.rb +2 -0
  93. data/lib/threatinator/cli/action_builder.rb +33 -0
  94. data/lib/threatinator/cli/list_action_builder.rb +19 -0
  95. data/lib/threatinator/cli/parser.rb +123 -0
  96. data/lib/threatinator/cli/run_action_builder.rb +41 -0
  97. data/lib/threatinator/cli.rb +19 -0
  98. data/lib/threatinator/config/base.rb +35 -0
  99. data/lib/threatinator/config/feed_search.rb +25 -0
  100. data/lib/threatinator/config/logger.rb +14 -0
  101. data/lib/threatinator/config.rb +7 -0
  102. data/lib/threatinator/decoder.rb +24 -0
  103. data/lib/threatinator/decoders/gzip.rb +30 -0
  104. data/lib/threatinator/event.rb +63 -0
  105. data/lib/threatinator/event_builder.rb +70 -0
  106. data/lib/threatinator/exceptions.rb +58 -0
  107. data/lib/threatinator/feed.rb +88 -0
  108. data/lib/threatinator/feed_builder.rb +161 -0
  109. data/lib/threatinator/feed_registry.rb +47 -0
  110. data/lib/threatinator/feed_runner.rb +177 -0
  111. data/lib/threatinator/fetcher.rb +22 -0
  112. data/lib/threatinator/fetchers/http.rb +50 -0
  113. data/lib/threatinator/filter.rb +12 -0
  114. data/lib/threatinator/filters/block.rb +18 -0
  115. data/lib/threatinator/filters/comments.rb +16 -0
  116. data/lib/threatinator/filters/whitespace.rb +19 -0
  117. data/lib/threatinator/logger.rb +66 -0
  118. data/lib/threatinator/logging.rb +20 -0
  119. data/lib/threatinator/model/base.rb +23 -0
  120. data/lib/threatinator/model/collection.rb +89 -0
  121. data/lib/threatinator/model/observables/fqdn_collection.rb +15 -0
  122. data/lib/threatinator/model/observables/ipv4.rb +33 -0
  123. data/lib/threatinator/model/observables/ipv4_collection.rb +14 -0
  124. data/lib/threatinator/model/observables/url_collection.rb +16 -0
  125. data/lib/threatinator/model/validations/type.rb +21 -0
  126. data/lib/threatinator/model/validations.rb +1 -0
  127. data/lib/threatinator/output.rb +50 -0
  128. data/lib/threatinator/parser.rb +23 -0
  129. data/lib/threatinator/parsers/csv/parser.rb +77 -0
  130. data/lib/threatinator/parsers/csv.rb +7 -0
  131. data/lib/threatinator/parsers/getline/parser.rb +45 -0
  132. data/lib/threatinator/parsers/getline.rb +8 -0
  133. data/lib/threatinator/parsers/json/adapters/oj.rb +65 -0
  134. data/lib/threatinator/parsers/json/parser.rb +45 -0
  135. data/lib/threatinator/parsers/json/record.rb +20 -0
  136. data/lib/threatinator/parsers/json.rb +8 -0
  137. data/lib/threatinator/parsers/xml/node.rb +79 -0
  138. data/lib/threatinator/parsers/xml/node_builder.rb +39 -0
  139. data/lib/threatinator/parsers/xml/parser.rb +44 -0
  140. data/lib/threatinator/parsers/xml/path.rb +70 -0
  141. data/lib/threatinator/parsers/xml/pattern.rb +53 -0
  142. data/lib/threatinator/parsers/xml/record.rb +14 -0
  143. data/lib/threatinator/parsers/xml/sax_document.rb +64 -0
  144. data/lib/threatinator/parsers/xml.rb +8 -0
  145. data/lib/threatinator/plugin_loader.rb +115 -0
  146. data/lib/threatinator/plugins/output/amqp/config.rb +18 -0
  147. data/lib/threatinator/plugins/output/amqp.rb +41 -0
  148. data/lib/threatinator/plugins/output/csv.rb +58 -0
  149. data/lib/threatinator/plugins/output/json/config.rb +14 -0
  150. data/lib/threatinator/plugins/output/json.rb +53 -0
  151. data/lib/threatinator/plugins/output/null.rb +17 -0
  152. data/lib/threatinator/plugins/output/rubydebug.rb +16 -0
  153. data/lib/threatinator/record.rb +22 -0
  154. data/lib/threatinator/registry.rb +53 -0
  155. data/lib/threatinator/util.rb +15 -0
  156. data/lib/threatinator.rb +3 -0
  157. data/spec/feeds/ET_block-ip_reputation_spec.rb +50 -0
  158. data/spec/feeds/ET_compromised-ip_reputation_spec.rb +47 -0
  159. data/spec/feeds/ET_openbadlist-ip_reputation_spec.rb +56 -0
  160. data/spec/feeds/alienvault-ip_reputation_spec.rb +46 -0
  161. data/spec/feeds/arbor_fastflux-domain_reputation_spec.rb +46 -0
  162. data/spec/feeds/arbor_ssh-ip_reputation_spec.rb +46 -0
  163. data/spec/feeds/autoshun_shunlist_spec.rb +38 -0
  164. data/spec/feeds/bambenek_c2_masterlist-domain_reputation_spec.rb +38 -0
  165. data/spec/feeds/bambenek_c2_masterlist-ip_reputation_spec.rb +39 -0
  166. data/spec/feeds/bambenek_dga_feed-domain_reputation_spec.rb +39 -0
  167. data/spec/feeds/berkeley-ip_reputation_spec.rb +47 -0
  168. data/spec/feeds/bitcash_cz_blacklist-ip_reputation_spec.rb +50 -0
  169. data/spec/feeds/blocklist_de_apache-ip_reputation_spec.rb +47 -0
  170. data/spec/feeds/blocklist_de_bots-ip_reputation_spec.rb +47 -0
  171. data/spec/feeds/blocklist_de_ftp-ip_reputation_spec.rb +47 -0
  172. data/spec/feeds/blocklist_de_imap-ip_reputation_spec.rb +47 -0
  173. data/spec/feeds/blocklist_de_pop3-ip_reputation_spec.rb +47 -0
  174. data/spec/feeds/blocklist_de_proftpd-ip_reputation_spec.rb +47 -0
  175. data/spec/feeds/blocklist_de_sip-ip_reputation_spec.rb +47 -0
  176. data/spec/feeds/blocklist_de_ssh-ip_reputation_spec.rb +47 -0
  177. data/spec/feeds/blocklist_de_strongips-ip_reputation_spec.rb +47 -0
  178. data/spec/feeds/botscout-ip_reputation_spec.rb +50 -0
  179. data/spec/feeds/cert_mxpoison-ip_reputation_spec.rb +47 -0
  180. data/spec/feeds/chaosreigns-ip_reputation_spec.rb +50 -0
  181. data/spec/feeds/ciarmy-ip_reputation_spec.rb +47 -0
  182. data/spec/feeds/cruzit-ip_reputation_spec.rb +47 -0
  183. data/spec/feeds/cydef_torexit-ip_reputation_spec.rb +47 -0
  184. data/spec/feeds/dan_me_uk_torlist-ip_reputation_spec.rb +47 -0
  185. data/spec/feeds/danger_bruteforce-ip_reputation_spec.rb +47 -0
  186. data/spec/feeds/data/ET_block-ip_reputation.txt +80 -0
  187. data/spec/feeds/data/ET_compromised-ip_reputation.txt +11 -0
  188. data/spec/feeds/data/ET_openbadlist-ip_reputation.txt +62 -0
  189. data/spec/feeds/data/alienvault-ip_reputation.txt +18 -0
  190. data/spec/feeds/data/arbor_domainlist.txt +11 -0
  191. data/spec/feeds/data/arbor_ssh.txt +16 -0
  192. data/spec/feeds/data/autoshun_shunlist.csv +20 -0
  193. data/spec/feeds/data/bambenek_c2-dommasterlist.csv +30 -0
  194. data/spec/feeds/data/bambenek_c2-ipmasterlist.csv +27 -0
  195. data/spec/feeds/data/bambenek_dga_feed.csv +42 -0
  196. data/spec/feeds/data/berkeley.txt +29 -0
  197. data/spec/feeds/data/bitcash_cz_blacklist.txt +7 -0
  198. data/spec/feeds/data/blocklist_de_apache-ip-reputation.txt +17 -0
  199. data/spec/feeds/data/blocklist_de_bots-ip-reputation.txt +15 -0
  200. data/spec/feeds/data/blocklist_de_ftp-ip-reputation.txt +7 -0
  201. data/spec/feeds/data/blocklist_de_imap-ip-reputation.txt +8 -0
  202. data/spec/feeds/data/blocklist_de_pop3-ip-reputation.txt +11 -0
  203. data/spec/feeds/data/blocklist_de_proftpd-ip-reputation.txt +12 -0
  204. data/spec/feeds/data/blocklist_de_sip-ip-reputation.txt +9 -0
  205. data/spec/feeds/data/blocklist_de_ssh-ip-reputation.txt +10 -0
  206. data/spec/feeds/data/blocklist_de_strongips-ip-reputation.txt +11 -0
  207. data/spec/feeds/data/botscout-ip-reputation.txt +713 -0
  208. data/spec/feeds/data/cert_mxpoison-ip_reputation.txt +17 -0
  209. data/spec/feeds/data/chaosreigns-ip-reputation.txt +26 -0
  210. data/spec/feeds/data/ciarmy-ip-reputation.txt +11 -0
  211. data/spec/feeds/data/cruzit-ip-reputation.txt +14 -0
  212. data/spec/feeds/data/cydef_torexit-ip_reputation.txt +27 -0
  213. data/spec/feeds/data/dan_me_uk_torlist-ip-reputation.txt +11 -0
  214. data/spec/feeds/data/danger_bruteforce-ip_reputation.txt +12 -0
  215. data/spec/feeds/data/dshield_topattackers.xml +4 -0
  216. data/spec/feeds/data/falconcrest_iplist.txt +345 -0
  217. data/spec/feeds/data/feodo_domainlist.txt +18 -0
  218. data/spec/feeds/data/feodo_iplist.txt +20 -0
  219. data/spec/feeds/data/h3x_asprox.txt +20 -0
  220. data/spec/feeds/data/hosts-file_hphostspartial_domainlist.txt +24 -0
  221. data/spec/feeds/data/infiltrated_iplist.txt +16 -0
  222. data/spec/feeds/data/infiltrated_vabl_iplist.txt +33 -0
  223. data/spec/feeds/data/isc_suspicious_high_domainlist.txt +26 -0
  224. data/spec/feeds/data/isc_suspicious_low_domainlist.txt +34 -0
  225. data/spec/feeds/data/isc_suspicious_medium_domainlist.txt +32 -0
  226. data/spec/feeds/data/malc0de_domainlist.txt +18 -0
  227. data/spec/feeds/data/malc0de_iplist.txt +14 -0
  228. data/spec/feeds/data/malwaredomainlist-url-reputation.txt +8 -0
  229. data/spec/feeds/data/malwaredomains_domainlist.txt +24 -0
  230. data/spec/feeds/data/malwaredomains_dyndns_domainlist.txt +34 -0
  231. data/spec/feeds/data/malwaredomains_justdomains_domainlist.txt +18 -0
  232. data/spec/feeds/data/mirc_domainlist.txt +31 -0
  233. data/spec/feeds/data/multiproxy_iplist.txt +15 -0
  234. data/spec/feeds/data/nothink_irc_iplist.txt +14 -0
  235. data/spec/feeds/data/nothink_ssh_iplist.txt +10 -0
  236. data/spec/feeds/data/openbl_iplist.txt +12 -0
  237. data/spec/feeds/data/openphish-url-reputation.txt +16 -0
  238. data/spec/feeds/data/packetmail_perimeterbad-ip_reputation.txt +44 -0
  239. data/spec/feeds/data/palevo_domainlist.txt +25 -0
  240. data/spec/feeds/data/palevo_iplist.txt +24 -0
  241. data/spec/feeds/data/phishtank-sample.json.gz +0 -0
  242. data/spec/feeds/data/sigmaproject_atma.return.gz +0 -0
  243. data/spec/feeds/data/sigmaproject_spyware.return.gz +0 -0
  244. data/spec/feeds/data/sigmaproject_webexploit.return.gz +0 -0
  245. data/spec/feeds/data/snort_bpf-ip_reputation.txt +16 -0
  246. data/spec/feeds/data/spyeye_domainlist.txt +16 -0
  247. data/spec/feeds/data/spyeye_iplist.txt +19 -0
  248. data/spec/feeds/data/steeman-ip-reputation.txt +13 -0
  249. data/spec/feeds/data/t-arend-de_ssh_iplist.txt +17 -0
  250. data/spec/feeds/data/the_haleys_ssh_iplist.txt +12 -0
  251. data/spec/feeds/data/trustedsec-ip-reputation.txt +12 -0
  252. data/spec/feeds/data/valid.json +2908 -0
  253. data/spec/feeds/data/virbl-ip_reputation.txt +14 -0
  254. data/spec/feeds/data/vxvault-url-reputation.txt +15 -0
  255. data/spec/feeds/data/yourcmc_ssh-ip_reputation.txt +27 -0
  256. data/spec/feeds/data/yoyo_adservers.txt +25 -0
  257. data/spec/feeds/data/zeus-ip_reputation.txt +285 -0
  258. data/spec/feeds/data/zeus_domainlist.txt +27 -0
  259. data/spec/feeds/dshield_attackers-top1000_spec.rb +39 -0
  260. data/spec/feeds/falconcrest-ip_reputation_spec.rb +39 -0
  261. data/spec/feeds/feodo-domain_reputation_spec.rb +47 -0
  262. data/spec/feeds/feodo-ip_reputation_spec.rb +47 -0
  263. data/spec/feeds/h3x_asprox-ip_reputation_spec.rb +50 -0
  264. data/spec/feeds/hosts-file_hphostspartial-domain_reputation_spec.rb +47 -0
  265. data/spec/feeds/infiltrated-ip_reputation_spec.rb +47 -0
  266. data/spec/feeds/infiltrated_vabl-ip_reputation_spec.rb +47 -0
  267. data/spec/feeds/isc_suspicious_high-domain_reputation_spec.rb +47 -0
  268. data/spec/feeds/isc_suspicious_low-domain_reputation_spec.rb +47 -0
  269. data/spec/feeds/isc_suspicious_medium-domain_reputation_spec.rb +47 -0
  270. data/spec/feeds/malc0de-domain_reputation_spec.rb +47 -0
  271. data/spec/feeds/malc0de-ip_reputation_spec.rb +47 -0
  272. data/spec/feeds/malwaredomainlist_url_reputation_spec.rb +50 -0
  273. data/spec/feeds/malwaredomains-domain_reputation_spec.rb +47 -0
  274. data/spec/feeds/malwaredomains_dyndns-domain_reputation_spec.rb +47 -0
  275. data/spec/feeds/malwaredomains_justdomains-domain_reputation_spec.rb +47 -0
  276. data/spec/feeds/mirc-domain_reputation_spec.rb +47 -0
  277. data/spec/feeds/multiproxy-ip_reputation_spec.rb +47 -0
  278. data/spec/feeds/nothink_irc-ip_reputation_spec.rb +47 -0
  279. data/spec/feeds/nothink_ssh-ip_reputation_spec.rb +47 -0
  280. data/spec/feeds/openbl-ip_reputation_spec.rb +47 -0
  281. data/spec/feeds/openphish_url_reputation_spec.rb +50 -0
  282. data/spec/feeds/packetmail_perimeterbad-ip_reputation_spec.rb +47 -0
  283. data/spec/feeds/palevo-domain_reputation_spec.rb +47 -0
  284. data/spec/feeds/palevo-ip_reputation_spec.rb +47 -0
  285. data/spec/feeds/phishtank_spec.rb +41 -0
  286. data/spec/feeds/sigmaproject_atma_spec.rb +62 -0
  287. data/spec/feeds/sigmaproject_spyware_spec.rb +63 -0
  288. data/spec/feeds/sigmaproject_webexploit_spec.rb +62 -0
  289. data/spec/feeds/snort_bpf-ip_reputation_spec.rb +47 -0
  290. data/spec/feeds/spyeye-domain_reputation_spec.rb +47 -0
  291. data/spec/feeds/spyeye-ip_reputation_spec.rb +47 -0
  292. data/spec/feeds/steeman-ip_reputation_spec.rb +50 -0
  293. data/spec/feeds/t-arend-de_ssh-ip_reputation_spec.rb +47 -0
  294. data/spec/feeds/the_haleys_ssh-ip_reputation_spec.rb +47 -0
  295. data/spec/feeds/trustedsec-ip_reputation_spec.rb +47 -0
  296. data/spec/feeds/virbl-ip_reputation_spec.rb +47 -0
  297. data/spec/feeds/vxvault_url_reputation_spec.rb +50 -0
  298. data/spec/feeds/yourcmc_ssh-ip_reputation_spec.rb +47 -0
  299. data/spec/feeds/yoyo_adservers_spec.rb +47 -0
  300. data/spec/feeds/zeus-domain_reputation_spec.rb +47 -0
  301. data/spec/feeds/zeus-ip_reputation_spec.rb +47 -0
  302. data/spec/fixtures/feed/provider1/feed1.feed +6 -0
  303. data/spec/fixtures/parsers/test.xml +13 -0
  304. data/spec/fixtures/parsers/test_self_closing.xml +20 -0
  305. data/spec/fixtures/plugins/bad/threatinator/plugins/test_error1/plugin.rb +1 -0
  306. data/spec/fixtures/plugins/bad/threatinator/plugins/test_missing1/plugin.rb +0 -0
  307. data/spec/fixtures/plugins/fake.rb +19 -0
  308. data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_a.rb +8 -0
  309. data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_b.rb +8 -0
  310. data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_c.rb +8 -0
  311. data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_d.rb +8 -0
  312. data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_e.rb +8 -0
  313. data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_f.rb +8 -0
  314. data/spec/spec_helper.rb +54 -0
  315. data/spec/support/bad_feeds/missing_fetcher.feed +7 -0
  316. data/spec/support/bad_feeds/missing_name.feed +6 -0
  317. data/spec/support/bad_feeds/missing_parser.feed +3 -0
  318. data/spec/support/bad_feeds/missing_provider.feed +5 -0
  319. data/spec/support/factories/event.rb +31 -0
  320. data/spec/support/factories/feed.rb +59 -0
  321. data/spec/support/factories/feed_builder.rb +65 -0
  322. data/spec/support/factories/feed_registry.rb +8 -0
  323. data/spec/support/factories/ipv4.rb +36 -0
  324. data/spec/support/factories/output.rb +11 -0
  325. data/spec/support/factories/record.rb +17 -0
  326. data/spec/support/factories/url.rb +34 -0
  327. data/spec/support/factories/xml_node.rb +33 -0
  328. data/spec/support/helpers/io.rb +11 -0
  329. data/spec/support/helpers/models.rb +13 -0
  330. data/spec/support/shared/action_builder.rb +47 -0
  331. data/spec/support/shared/decoder.rb +70 -0
  332. data/spec/support/shared/feed_runner_observer.rb +136 -0
  333. data/spec/support/shared/feeds.rb +233 -0
  334. data/spec/support/shared/fetcher.rb +48 -0
  335. data/spec/support/shared/filter.rb +14 -0
  336. data/spec/support/shared/io-like.rb +7 -0
  337. data/spec/support/shared/model/collection.rb +164 -0
  338. data/spec/support/shared/output.rb +120 -0
  339. data/spec/support/shared/parsers.rb +51 -0
  340. data/spec/support/shared/record.rb +111 -0
  341. data/spec/threatinator/actions/list/action_spec.rb +148 -0
  342. data/spec/threatinator/actions/run/action_spec.rb +106 -0
  343. data/spec/threatinator/actions/run/config_spec.rb +39 -0
  344. data/spec/threatinator/actions/run/coverage_observer_spec.rb +151 -0
  345. data/spec/threatinator/actions/run/output_config_spec.rb +89 -0
  346. data/spec/threatinator/actions/run/status_observer_spec.rb +86 -0
  347. data/spec/threatinator/cli/list_action_builder_spec.rb +57 -0
  348. data/spec/threatinator/cli/run_action_builder_spec.rb +133 -0
  349. data/spec/threatinator/cli_spec.rb +175 -0
  350. data/spec/threatinator/config/base_spec.rb +39 -0
  351. data/spec/threatinator/config/feed_search_spec.rb +76 -0
  352. data/spec/threatinator/decoders/gzip_spec.rb +75 -0
  353. data/spec/threatinator/event_builder_spec.rb +123 -0
  354. data/spec/threatinator/event_spec.rb +254 -0
  355. data/spec/threatinator/event_spec.rb.new +319 -0
  356. data/spec/threatinator/feed_builder_spec.rb +633 -0
  357. data/spec/threatinator/feed_registry_spec.rb +198 -0
  358. data/spec/threatinator/feed_runner_spec.rb +372 -0
  359. data/spec/threatinator/feed_spec.rb +169 -0
  360. data/spec/threatinator/fetcher_spec.rb +12 -0
  361. data/spec/threatinator/fetchers/http_spec.rb +32 -0
  362. data/spec/threatinator/filter_spec.rb +13 -0
  363. data/spec/threatinator/filters/block_spec.rb +16 -0
  364. data/spec/threatinator/filters/comments_spec.rb +13 -0
  365. data/spec/threatinator/filters/whitespace_spec.rb +12 -0
  366. data/spec/threatinator/logger_spec.rb +29 -0
  367. data/spec/threatinator/model/observables/fqdn_collection_spec.rb +41 -0
  368. data/spec/threatinator/model/observables/ipv4_collection_spec.rb +36 -0
  369. data/spec/threatinator/model/observables/ipv4_spec.rb +75 -0
  370. data/spec/threatinator/model/observables/url_collection_spec.rb +45 -0
  371. data/spec/threatinator/model/validations/type_spec.rb +37 -0
  372. data/spec/threatinator/parser_spec.rb +13 -0
  373. data/spec/threatinator/parsers/csv/parser_spec.rb +202 -0
  374. data/spec/threatinator/parsers/getline/parser_spec.rb +83 -0
  375. data/spec/threatinator/parsers/json/parser_spec.rb +106 -0
  376. data/spec/threatinator/parsers/json/record_spec.rb +30 -0
  377. data/spec/threatinator/parsers/xml/node_spec.rb +335 -0
  378. data/spec/threatinator/parsers/xml/parser_spec.rb +263 -0
  379. data/spec/threatinator/parsers/xml/path_spec.rb +209 -0
  380. data/spec/threatinator/parsers/xml/pattern_spec.rb +72 -0
  381. data/spec/threatinator/parsers/xml/record_spec.rb +27 -0
  382. data/spec/threatinator/plugin_loader_spec.rb +238 -0
  383. data/spec/threatinator/plugins/output/csv_spec.rb +47 -0
  384. data/spec/threatinator/plugins/output/null_spec.rb +17 -0
  385. data/spec/threatinator/plugins/output/rubydebug_spec.rb +37 -0
  386. data/spec/threatinator/record_spec.rb +19 -0
  387. data/spec/threatinator/registry_spec.rb +97 -0
  388. data/spec/threatinator/runner_spec.rb +273 -0
  389. metadata +674 -0
@@ -0,0 +1,111 @@
1
+ shared_examples_for 'a record when compared to an identically configured record' do
2
+ let(:record1) { described_class.new(data, opts) }
3
+ let(:record2) { described_class.new(data2, opts2) }
4
+ specify "record1 should == record2" do
5
+ expect(record1).to be == record2
6
+ end
7
+ specify "record2 should == record1" do
8
+ expect(record2).to be == record1
9
+ end
10
+ specify "record1 should eql? record2" do
11
+ expect(record1).to eql record2
12
+ end
13
+ specify "record2 should eql? record1" do
14
+ expect(record2).to eql record1
15
+ end
16
+ end
17
+
18
+ shared_examples_for 'a record when compared to a differently configured record' do
19
+ let(:record1) { described_class.new(data, opts) }
20
+ let(:record2) { described_class.new(data2, opts2) }
21
+ specify "record1 should not == record2" do
22
+ expect(record1).not_to be == record2
23
+ end
24
+ specify "record2 should not == record1" do
25
+ expect(record2).not_to be == record1
26
+ end
27
+ specify "record1 should not eql? record2" do
28
+ expect(record1).not_to eql record2
29
+ end
30
+ specify "record2 should not eql? record1" do
31
+ expect(record2).not_to eql record1
32
+ end
33
+ end
34
+
35
+ shared_examples_for 'a record' do
36
+ let(:record) { described_class.new(data, opts) }
37
+ context "when compared to itself" do
38
+ it_should_behave_like 'a record when compared to an identically configured record' do
39
+ let(:data2) { Marshal.load(Marshal.dump(data)) }
40
+ let(:opts2) { Marshal.load(Marshal.dump(opts)) }
41
+ end
42
+ end
43
+ describe "initialization options" do
44
+ describe "data" do
45
+ it "should be accessible via #data" do
46
+ expect(record.data).to eq(data)
47
+ end
48
+ end
49
+ describe ":line_number" do
50
+ context "when not set" do
51
+ it "should default to nil" do
52
+ expect(record.line_number).to be_nil
53
+ end
54
+ end
55
+ context "when set" do
56
+ before :each do
57
+ opts[:line_number] = 1234
58
+ end
59
+ it "should be readable via #line_number" do
60
+ expect(record.line_number).to eq(1234)
61
+ end
62
+
63
+ it_should_behave_like 'a record when compared to an identically configured record' do
64
+ let(:data2) { Marshal.load(Marshal.dump(data)) }
65
+ let(:opts2) { Marshal.load(Marshal.dump(opts)) }
66
+ end
67
+ end
68
+ end
69
+ describe ":pos_start" do
70
+ context "when not set" do
71
+ it "should default to nil" do
72
+ expect(record.pos_start).to be_nil
73
+ end
74
+ end
75
+ context "when set" do
76
+ before :each do
77
+ opts[:pos_start] = 999
78
+ end
79
+ it "should be readable via #pos_start" do
80
+ expect(record.pos_start).to eq(999)
81
+ end
82
+
83
+ it_should_behave_like 'a record when compared to an identically configured record' do
84
+ let(:data2) { Marshal.load(Marshal.dump(data)) }
85
+ let(:opts2) { Marshal.load(Marshal.dump(opts)) }
86
+ end
87
+ end
88
+ end
89
+ describe ":pos_end" do
90
+ context "when not set" do
91
+ it "should default to nil" do
92
+ expect(record.pos_end).to be_nil
93
+ end
94
+ end
95
+ context "when set" do
96
+ before :each do
97
+ opts[:pos_end] = 555
98
+ end
99
+
100
+ it "should be readable via #pos_end" do
101
+ expect(record.pos_end).to eq(555)
102
+ end
103
+
104
+ it_should_behave_like 'a record when compared to an identically configured record' do
105
+ let(:data2) { Marshal.load(Marshal.dump(data)) }
106
+ let(:opts2) { Marshal.load(Marshal.dump(opts)) }
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/actions/list/action'
3
+ require 'threatinator/actions/list/config'
4
+ require 'multi_json'
5
+
6
+ describe Threatinator::Actions::List::Action do
7
+ let(:feed_registry) { build(:feed_registry) }
8
+ let(:config) { Threatinator::Actions::List::Config.new }
9
+ let(:action) { described_class.new(feed_registry, config) }
10
+
11
+ shared_examples_for 'table output' do
12
+ describe "the header row, header separator, and footer separator" do
13
+ it "should vary the width of 'provider' based on the longest provider name" do
14
+
15
+ 1.upto(3) do |i|
16
+ feed_registry.register(build(:feed, :http, url: "http://#{i}", name:i.to_s, provider: ('A' * (10 * i)), event_types: [:unknown]))
17
+ end
18
+
19
+ output = temp_stdout do
20
+ action.exec
21
+ end
22
+ lines = output.lines.to_a
23
+
24
+ expect(lines[0]).to eq("provider name type link/path event_types\n")
25
+ expect(lines[1]).to eq("------------------------------ ---- ---- --------- -----------\n")
26
+ expect(lines[-2]).to eq("------------------------------ ---- ---- --------- -----------\n")
27
+ end
28
+
29
+ it "should vary the width of 'name' based on the longest feed name" do
30
+ 1.upto(3) do |i|
31
+ feed_registry.register(build(:feed, :http, url: "http://#{i}", provider:i.to_s, name: ('A' * (10 * i)), event_types: [:unknown]))
32
+ end
33
+
34
+ output = temp_stdout do
35
+ action.exec
36
+ end
37
+ lines = output.lines.to_a
38
+ expect(lines[0]).to eq("provider name type link/path event_types\n")
39
+ expect(lines[1]).to eq("-------- ------------------------------ ---- --------- -----------\n")
40
+ expect(lines[-2]).to eq("-------- ------------------------------ ---- --------- -----------\n")
41
+ end
42
+
43
+ it "should vary the width of 'link/path' based on the longest link name" do
44
+ 1.upto(3) do |i|
45
+ feed_registry.register(build(:feed, :http, url: 'http://' + ('A' * (i * 10)), provider:i.to_s,name:i.to_s, event_types: [:unknown]))
46
+ end
47
+
48
+ output = temp_stdout do
49
+ action.exec
50
+ end
51
+ lines = output.lines.to_a
52
+ expect(lines[0]).to eq("provider name type link/path event_types\n")
53
+ expect(lines[1]).to eq("-------- ---- ---- ------------------------------------- -----------\n")
54
+ expect(lines[-2]).to eq("-------- ---- ---- ------------------------------------- -----------\n")
55
+ end
56
+ end
57
+
58
+ describe "the list of feeds" do
59
+ it "should be sorted by provider name and then feed name" do
60
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_c', event_types: [:unknown] ))
61
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_d', event_types: [:unknown] ))
62
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_a', event_types: [:unknown] ))
63
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_d', event_types: [:unknown] ))
64
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_c', event_types: [:unknown] ))
65
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_a', event_types: [:unknown] ))
66
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_b', event_types: [:unknown] ))
67
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_b', event_types: [:unknown] ))
68
+
69
+ output = temp_stdout do
70
+ action.exec
71
+ end
72
+ lines = output.lines.to_a
73
+ expect(lines[2]).to match(/^provider_a feed_a .*$/)
74
+ expect(lines[3]).to match(/^provider_a feed_b .*$/)
75
+ expect(lines[4]).to match(/^provider_a feed_c .*$/)
76
+ expect(lines[5]).to match(/^provider_a feed_d .*$/)
77
+ expect(lines[6]).to match(/^provider_b feed_a .*$/)
78
+ expect(lines[7]).to match(/^provider_b feed_b .*$/)
79
+ expect(lines[8]).to match(/^provider_b feed_c .*$/)
80
+ expect(lines[9]).to match(/^provider_b feed_d .*$/)
81
+ end
82
+ end
83
+
84
+ describe "the footer" do
85
+ it "should indicate the number of feeds" do
86
+ 20.times do |i|
87
+ feed_registry.register(build(:feed))
88
+ end
89
+ output = temp_stdout do
90
+ action.exec
91
+ end
92
+ lines = output.lines.to_a
93
+ expect(lines[-1]).to eq("Total: 20\n")
94
+ end
95
+ end
96
+ end
97
+
98
+ shared_examples_for 'json output' do
99
+ describe "the output" do
100
+ it "should be sorted by provider name and then feed name" do
101
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_c', event_types: [:unknown] ))
102
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_d', event_types: [:unknown] ))
103
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_a', event_types: [:unknown] ))
104
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_d', event_types: [:unknown] ))
105
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_c', event_types: [:unknown] ))
106
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_a', event_types: [:unknown] ))
107
+ feed_registry.register(build(:feed, provider: 'provider_b', name: 'feed_b', event_types: [:unknown] ))
108
+ feed_registry.register(build(:feed, provider: 'provider_a', name: 'feed_b', event_types: [:unknown] ))
109
+
110
+ output = temp_stdout do
111
+ action.exec
112
+ end
113
+
114
+ data = MultiJson.load(output)
115
+ expect(data).to match(
116
+ [
117
+ {'provider' => 'provider_a', 'name' => 'feed_a', 'type' => kind_of(String), 'link' => kind_of(String)},
118
+ {'provider' => 'provider_a', 'name' => 'feed_b', 'type' => kind_of(String), 'link' => kind_of(String)},
119
+ {'provider' => 'provider_a', 'name' => 'feed_c', 'type' => kind_of(String), 'link' => kind_of(String)},
120
+ {'provider' => 'provider_a', 'name' => 'feed_d', 'type' => kind_of(String), 'link' => kind_of(String)},
121
+ {'provider' => 'provider_b', 'name' => 'feed_a', 'type' => kind_of(String), 'link' => kind_of(String)},
122
+ {'provider' => 'provider_b', 'name' => 'feed_b', 'type' => kind_of(String), 'link' => kind_of(String)},
123
+ {'provider' => 'provider_b', 'name' => 'feed_c', 'type' => kind_of(String), 'link' => kind_of(String)},
124
+ {'provider' => 'provider_b', 'name' => 'feed_d', 'type' => kind_of(String), 'link' => kind_of(String)}
125
+ ]
126
+ )
127
+ end
128
+ end
129
+ end
130
+
131
+ context "when list.format is not set" do
132
+ it_behaves_like 'table output'
133
+ end
134
+ context "when list.format == 'table'" do
135
+ before :each do
136
+ config.format = 'table'
137
+ end
138
+ it_behaves_like 'table output'
139
+ end
140
+
141
+ context "when list.format == 'json'" do
142
+ before :each do
143
+ config.format = 'json'
144
+ end
145
+ it_behaves_like 'json output'
146
+ end
147
+
148
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/actions/run/action'
3
+ require 'threatinator/actions/run/config'
4
+ require 'threatinator/plugin_loader'
5
+
6
+ describe Threatinator::Actions::Run::Action do
7
+ let(:feed_registry) { build(:feed_registry) }
8
+ let(:feed_runner) { double('feed runner') }
9
+ let(:plugin_loader) { Threatinator::PluginLoader.new }
10
+ let(:config_class) { Threatinator::Actions::Run::Config.generate(plugin_loader) }
11
+ let(:config) { config_class.new }
12
+ let(:action) { described_class.new(feed_registry, config) }
13
+ let(:feed) { build(:feed, provider: "my_provider", name: "my_name") }
14
+
15
+ before :each do
16
+ feed_registry.register(feed)
17
+ end
18
+
19
+ context "when configured with feed provider and name that exists within the registry" do
20
+ let(:output) { double('mock output') }
21
+ let(:observer) { double('observer') }
22
+ before :each do
23
+ config.feed_provider = "my_provider"
24
+ config.feed_name = "my_name"
25
+
26
+ allow(feed_registry).to receive(:get).and_call_original
27
+ allow(config.output).to receive(:build_output).and_return(output)
28
+ allow(Threatinator::FeedRunner).to receive(:new).and_return(feed_runner)
29
+ allow(feed_runner).to receive(:run)
30
+ allow(feed_runner).to receive(:add_observer)
31
+ end
32
+
33
+ describe "#exec" do
34
+
35
+ it "queries the feed registry for the provider and name" do
36
+ action.exec
37
+ expect(feed_registry).to have_received(:get).with("my_provider", "my_name")
38
+ end
39
+
40
+ it "builds the output using config.output.build_output" do
41
+ action.exec
42
+ expect(config.output).to have_received(:build_output)
43
+ end
44
+
45
+ it "runs the feed" do
46
+ action.exec
47
+ expect(feed_runner).to have_received(:run)
48
+ end
49
+
50
+ context "when a record was missed" do
51
+ let(:status_observer) { Threatinator::Actions::Run::StatusObserver.new }
52
+ before :each do
53
+ allow(Threatinator::Actions::Run::StatusObserver).to receive(:new).and_return(status_observer)
54
+ allow(status_observer).to receive(:missed?).and_return(true)
55
+ end
56
+
57
+ it "logs an error message" do
58
+ expect(action.logger).to receive(:error).with(/records were MISSED/)
59
+ action.exec
60
+ end
61
+ end
62
+
63
+ context "when a record had an error" do
64
+ let(:status_observer) { Threatinator::Actions::Run::StatusObserver.new }
65
+ before :each do
66
+ allow(Threatinator::Actions::Run::StatusObserver).to receive(:new).and_return(status_observer)
67
+ allow(status_observer).to receive(:errors?).and_return(true)
68
+ end
69
+
70
+ it "logs an error message" do
71
+ expect(action.logger).to receive(:error).with(/records had errors/)
72
+ action.exec
73
+ end
74
+ end
75
+ end
76
+
77
+ context "when configured with an observer" do
78
+ before :each do
79
+ allow(feed_runner).to receive(:add_observer)
80
+ config.observers = [ observer ]
81
+ end
82
+
83
+ describe "#exec" do
84
+ it "adds the observer to FeedRunner" do
85
+ expect(feed_runner).to receive(:add_observer).with(observer)
86
+ action.exec
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ context "when the registry does not contain the configured feed_provider or feed_name" do
93
+ before :each do
94
+ config.feed_provider = "unknown_provider"
95
+ config.feed_name = "unknown_feed_name"
96
+ end
97
+ describe "#exec" do
98
+ it "raises Threatinator::Exceptions::UnknownFeed" do
99
+ expect {
100
+ action.exec
101
+ }.to raise_error(Threatinator::Exceptions::UnknownFeed)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/actions/run/config'
3
+ require 'threatinator/plugin_loader'
4
+ require 'fixtures/plugins/fake'
5
+
6
+ describe Threatinator::Actions::Run::Config do
7
+
8
+ let(:plugin_loader) { Threatinator::PluginLoader.new }
9
+
10
+ describe ".generate(plugin_loader)" do
11
+ before :each do
12
+ allow(Threatinator::Actions::Run::OutputConfig).to receive(:generate).and_call_original
13
+ plugin_loader.register_plugin(:output, :plugin1, FakeOutputPlugins::Plugin1)
14
+ plugin_loader.register_plugin(:output, :plugin2, FakeOutputPlugins::Plugin2)
15
+ plugin_loader.register_plugin(:output, :plugin3, FakeOutputPlugins::Plugin3)
16
+ @generated_class = described_class.generate(plugin_loader)
17
+ end
18
+
19
+ let(:generated_class) { @generated_class }
20
+
21
+ it "returns a subclass of Threatinator::Config::Base" do
22
+ expect(generated_class.superclass).to be(Threatinator::Config::Base)
23
+ end
24
+
25
+ it "generates a new Output config class using the plugin_loader" do
26
+ expect(Threatinator::Actions::Run::OutputConfig).to have_received(:generate).with(plugin_loader)
27
+ end
28
+
29
+ describe "an instance" do
30
+ let(:config) { generated_class.new }
31
+ describe "#output" do
32
+ specify "returns an instance of a subclass of Threatinator::Config::Base" do
33
+ expect(config.output.class.superclass).to be(Threatinator::Config::Base)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/actions/run/coverage_observer'
3
+
4
+ describe Threatinator::Actions::Run::CoverageObserver do
5
+ before :each do
6
+ @tmpdir = Dir.mktmpdir
7
+ end
8
+
9
+ after :each do
10
+ observer.update(:end)
11
+ FileUtils.remove_entry_secure @tmpdir
12
+ end
13
+
14
+ let(:filename) { File.join(@tmpdir, "coverage.csv") }
15
+ let(:observer) { described_class.new(filename) }
16
+
17
+ it_should_behave_like "a FeedRunner observer"
18
+
19
+ context "#update(:start)" do
20
+ it "creates the file specified by filename" do
21
+ expect(File.exist?(filename)).to eq(false)
22
+ observer.update(:start)
23
+ expect(File.exist?(filename)).to eq(true)
24
+ end
25
+ end
26
+
27
+ context "#update(:end)" do
28
+ before :each do
29
+ observer.update(:start)
30
+ end
31
+
32
+ context "when at least one record has been written" do
33
+ before :each do
34
+ observer.update(:record_parsed, build(:record), [ build(:event) ])
35
+ observer.update(:end)
36
+ end
37
+
38
+ specify "the first line is the header" do
39
+ data = File.read(filename)
40
+ expect(data.lines.to_a.first).to eq("status,event_count,line_number,pos_start,pos_end,data,message\n")
41
+ end
42
+
43
+ it "closes the file so that no more records will be written" do
44
+ data_before = File.read(filename)
45
+ 10.times do
46
+ observer.update(:record_missed, build(:record))
47
+ end
48
+ data_after = File.read(filename)
49
+ expect(data_before).to eq(data_after)
50
+ end
51
+ end
52
+ end
53
+
54
+ context "#update(:record_filtered, record)" do
55
+ before :each do
56
+ observer.update(:start)
57
+ end
58
+
59
+ it "writes a csv entry to the file indicating that it was filtered" do
60
+ record = build(:record, line_number: 23, pos_start: 99, pos_end: 105, data: "foobar\r\n")
61
+ observer.update(:record_filtered, record)
62
+ observer.update(:end)
63
+ csv = CSV.read(filename, headers: true, header_converters: :symbol)
64
+ expect(csv[-1].to_hash).to eq(
65
+ status: "filtered",
66
+ event_count: "0",
67
+ line_number: "23",
68
+ pos_start: "99",
69
+ pos_end: "105",
70
+ data: '"foobar\r\n"',
71
+ message: ''
72
+ )
73
+ end
74
+ end
75
+
76
+ context "#update(:record_filtered, record)" do
77
+ before :each do
78
+ observer.update(:start)
79
+ end
80
+
81
+ it "writes a csv entry to the file indicating that it was missed" do
82
+ record = build(:record, line_number: 22, pos_start: 98, pos_end: 104, data: "blabla\r\n")
83
+ observer.update(:record_filtered, record)
84
+ observer.update(:end)
85
+ csv = CSV.read(filename, headers: true, header_converters: :symbol)
86
+ expect(csv[-1].to_hash).to eq(
87
+ status: "filtered",
88
+ event_count: "0",
89
+ line_number: "22",
90
+ pos_start: "98",
91
+ pos_end: "104",
92
+ data: '"blabla\r\n"',
93
+ message: ''
94
+ )
95
+ end
96
+ end
97
+
98
+ context "#update(:record_parsed, record, events)" do
99
+ before :each do
100
+ observer.update(:start)
101
+ end
102
+
103
+ let(:record) { build(:record, line_number: 1, pos_start: 0, pos_end: 10, data: "woofwoof\r\n") }
104
+ let(:events) { [ build(:event), build(:event) ] }
105
+
106
+ it "writes a csv entry to the file indicating that it was parsed, with the number of events" do
107
+ observer.update(:record_parsed, record, events)
108
+ observer.update(:end)
109
+ csv = CSV.read(filename, headers: true, header_converters: :symbol)
110
+ expect(csv[-1].to_hash).to eq(
111
+ status: "parsed",
112
+ event_count: "2",
113
+ line_number: "1",
114
+ pos_start: "0",
115
+ pos_end: "10",
116
+ data: '"woofwoof\r\n"',
117
+ message: ''
118
+ )
119
+ end
120
+ end
121
+
122
+ context "#update(:record_error, record, errors)" do
123
+ before :each do
124
+ observer.update(:start)
125
+ end
126
+
127
+ let(:record) { build(:record, line_number: 1, pos_start: 0, pos_end: 10, data: "woofwoof\r\n") }
128
+ let(:errors) {
129
+ [
130
+ Threatinator::Exceptions::EventBuildError.new("error 1"),
131
+ Threatinator::Exceptions::EventBuildError.new("error 2"),
132
+ Threatinator::Exceptions::EventBuildError.new("error 3")
133
+ ]
134
+ }
135
+
136
+ it "writes a csv entry to the file indicating it encountered an error, with the error messages" do
137
+ observer.update(:record_error, record, errors)
138
+ observer.update(:end)
139
+ csv = CSV.read(filename, headers: true, header_converters: :symbol)
140
+ expect(csv[-1].to_hash).to eq(
141
+ status: "error",
142
+ event_count: "0",
143
+ line_number: "1",
144
+ pos_start: "0",
145
+ pos_end: "10",
146
+ data: '"woofwoof\r\n"',
147
+ message: 'error 1, error 2, error 3'
148
+ )
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/actions/run/output_config'
3
+ require 'threatinator/plugin_loader'
4
+ require 'fixtures/plugins/fake'
5
+
6
+ describe Threatinator::Actions::Run::OutputConfig do
7
+ let(:plugin_loader) { Threatinator::PluginLoader.new }
8
+
9
+ describe ".generate(plugin_loader)" do
10
+ before :each do
11
+ plugin_loader.register_plugin(:output, :plugin1, FakeOutputPlugins::Plugin1)
12
+ plugin_loader.register_plugin(:output, :plugin2, FakeOutputPlugins::Plugin2)
13
+ plugin_loader.register_plugin(:output, :plugin3, FakeOutputPlugins::Plugin3)
14
+ end
15
+
16
+ let(:generated_class) { described_class.generate(plugin_loader) }
17
+ it "returns a subclass of Threatinator::Config::Base" do
18
+ expect(generated_class.superclass).to be(Threatinator::Config::Base)
19
+ end
20
+
21
+ describe "#formats" do
22
+ it "returns an array containing all the registered output format names" do
23
+ expect(generated_class.formats).to contain_exactly('plugin1', 'plugin2', 'plugin3')
24
+ end
25
+ end
26
+
27
+ describe "#formats_str" do
28
+ it "returns a string of the #formats sorted alphabetically" do
29
+ expect(generated_class.formats_str).to eq('plugin1, plugin2, plugin3')
30
+ end
31
+ end
32
+
33
+ describe "attributes" do
34
+ describe ":format" do
35
+ describe "description" do
36
+ it "should describe the output and the available formats" do
37
+ a = generated_class.attribute_set[:format]
38
+ desc_proc = a.options[:description]
39
+ ret = desc_proc.call(generated_class, a)
40
+ expect(ret).to eq('Output format (plugin1, plugin2, plugin3)')
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "an instance" do
47
+ let(:config) { generated_class.new }
48
+ specify "has an attribute for each plugin name that is an instance of that plugin's config" do
49
+ expect(config.plugin1).to be_a(FakeOutputPlugins::Plugin1::Config)
50
+ expect(config.plugin1).to respond_to(:foo)
51
+ expect(config.plugin2).to be_a(FakeOutputPlugins::Plugin2::Config)
52
+ expect(config.plugin2).to respond_to(:bar)
53
+ expect(config.plugin3).to be_a(FakeOutputPlugins::Plugin3::Config)
54
+ expect(config.plugin3).to respond_to(:woof)
55
+ end
56
+
57
+ describe "#build_output" do
58
+ it "raises UnknownPlugin when no plugin is found for the value of #format" do
59
+ config.format = :asdf
60
+ expect {
61
+ config.build_output
62
+ }.to raise_error(Threatinator::Exceptions::UnknownPlugin)
63
+ end
64
+
65
+ it "raises CouldNotFindOutputConfigError if there is no config for the #format" do
66
+ config.format = :plugin1
67
+ config.plugin1 = nil
68
+ expect {
69
+ config.build_output
70
+ }.to raise_error(Threatinator::Exceptions::CouldNotFindOutputConfigError)
71
+ end
72
+
73
+ context "when #format is associated with a reigstered plugin" do
74
+ it "initializes the output plugin with the plugin's config" do
75
+ config.format = :plugin2
76
+ expect(FakeOutputPlugins::Plugin2).to receive(:new).with(config.plugin2)
77
+ config.build_output
78
+ end
79
+
80
+ it "returns an instance of the output plugin" do
81
+ config.format = :plugin3
82
+ expect(config.build_output).to be_a(FakeOutputPlugins::Plugin3)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+