threatinator 0.1.1

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 (219) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +23 -0
  3. data/CONTRIBUTING.md +119 -0
  4. data/Gemfile +28 -0
  5. data/LICENSE +165 -0
  6. data/README.md +45 -0
  7. data/Rakefile +45 -0
  8. data/VERSION +1 -0
  9. data/bin/threatinator +5 -0
  10. data/lib/threatinator.rb +3 -0
  11. data/lib/threatinator/action.rb +14 -0
  12. data/lib/threatinator/actions/list.rb +2 -0
  13. data/lib/threatinator/actions/list/action.rb +53 -0
  14. data/lib/threatinator/actions/list/config.rb +10 -0
  15. data/lib/threatinator/actions/run.rb +2 -0
  16. data/lib/threatinator/actions/run/action.rb +45 -0
  17. data/lib/threatinator/actions/run/config.rb +32 -0
  18. data/lib/threatinator/actions/run/coverage_observer.rb +54 -0
  19. data/lib/threatinator/actions/run/output_config.rb +59 -0
  20. data/lib/threatinator/cli.rb +13 -0
  21. data/lib/threatinator/cli/action_builder.rb +33 -0
  22. data/lib/threatinator/cli/list_action_builder.rb +19 -0
  23. data/lib/threatinator/cli/parser.rb +113 -0
  24. data/lib/threatinator/cli/run_action_builder.rb +41 -0
  25. data/lib/threatinator/config.rb +6 -0
  26. data/lib/threatinator/config/base.rb +35 -0
  27. data/lib/threatinator/config/feed_search.rb +25 -0
  28. data/lib/threatinator/decoder.rb +24 -0
  29. data/lib/threatinator/decoders/gzip.rb +30 -0
  30. data/lib/threatinator/event.rb +27 -0
  31. data/lib/threatinator/event_builder.rb +41 -0
  32. data/lib/threatinator/exceptions.rb +61 -0
  33. data/lib/threatinator/feed.rb +82 -0
  34. data/lib/threatinator/feed_builder.rb +156 -0
  35. data/lib/threatinator/feed_registry.rb +47 -0
  36. data/lib/threatinator/feed_runner.rb +118 -0
  37. data/lib/threatinator/fetcher.rb +22 -0
  38. data/lib/threatinator/fetchers/http.rb +46 -0
  39. data/lib/threatinator/filter.rb +12 -0
  40. data/lib/threatinator/filters/block.rb +18 -0
  41. data/lib/threatinator/filters/comments.rb +16 -0
  42. data/lib/threatinator/filters/whitespace.rb +19 -0
  43. data/lib/threatinator/output.rb +50 -0
  44. data/lib/threatinator/parser.rb +23 -0
  45. data/lib/threatinator/parsers/csv.rb +7 -0
  46. data/lib/threatinator/parsers/csv/parser.rb +77 -0
  47. data/lib/threatinator/parsers/getline.rb +8 -0
  48. data/lib/threatinator/parsers/getline/parser.rb +45 -0
  49. data/lib/threatinator/parsers/json.rb +8 -0
  50. data/lib/threatinator/parsers/json/adapters/oj.rb +65 -0
  51. data/lib/threatinator/parsers/json/parser.rb +45 -0
  52. data/lib/threatinator/parsers/json/record.rb +20 -0
  53. data/lib/threatinator/parsers/xml.rb +8 -0
  54. data/lib/threatinator/parsers/xml/node.rb +79 -0
  55. data/lib/threatinator/parsers/xml/node_builder.rb +39 -0
  56. data/lib/threatinator/parsers/xml/parser.rb +44 -0
  57. data/lib/threatinator/parsers/xml/path.rb +70 -0
  58. data/lib/threatinator/parsers/xml/pattern.rb +53 -0
  59. data/lib/threatinator/parsers/xml/record.rb +14 -0
  60. data/lib/threatinator/parsers/xml/sax_document.rb +64 -0
  61. data/lib/threatinator/plugin_loader.rb +115 -0
  62. data/lib/threatinator/plugins/output/csv.rb +47 -0
  63. data/lib/threatinator/plugins/output/null.rb +17 -0
  64. data/lib/threatinator/plugins/output/rubydebug.rb +16 -0
  65. data/lib/threatinator/property_definer.rb +101 -0
  66. data/lib/threatinator/record.rb +22 -0
  67. data/lib/threatinator/registry.rb +53 -0
  68. data/lib/threatinator/util.rb +15 -0
  69. data/spec/feeds/ET_compromised-ip_reputation_spec.rb +50 -0
  70. data/spec/feeds/alienvault-ip_reputation_spec.rb +50 -0
  71. data/spec/feeds/arbor_fastflux-domain_reputation_spec.rb +50 -0
  72. data/spec/feeds/arbor_ssh-ip_reputation_spec.rb +50 -0
  73. data/spec/feeds/autoshun_shunlist_spec.rb +42 -0
  74. data/spec/feeds/blocklist_de_apache-ip_reputation_spec.rb +50 -0
  75. data/spec/feeds/blocklist_de_bots-ip_reputation_spec.rb +50 -0
  76. data/spec/feeds/blocklist_de_ftp-ip_reputation_spec.rb +50 -0
  77. data/spec/feeds/blocklist_de_imap-ip_reputation_spec.rb +50 -0
  78. data/spec/feeds/blocklist_de_pop3-ip_reputation_spec.rb +50 -0
  79. data/spec/feeds/blocklist_de_proftpd-ip_reputation_spec.rb +50 -0
  80. data/spec/feeds/blocklist_de_sip-ip_reputation_spec.rb +50 -0
  81. data/spec/feeds/blocklist_de_ssh-ip_reputation_spec.rb +50 -0
  82. data/spec/feeds/blocklist_de_strongips-ip_reputation_spec.rb +50 -0
  83. data/spec/feeds/ciarmy-ip_reputation_spec.rb +50 -0
  84. data/spec/feeds/cruzit-ip_reputation_spec.rb +50 -0
  85. data/spec/feeds/dan_me_uk_torlist-ip_reputation_spec.rb +50 -0
  86. data/spec/feeds/data/ET_compromised-ip_reputation.txt +11 -0
  87. data/spec/feeds/data/alienvault-ip_reputation.txt +18 -0
  88. data/spec/feeds/data/arbor_domainlist.txt +11 -0
  89. data/spec/feeds/data/arbor_ssh.txt +16 -0
  90. data/spec/feeds/data/autoshun_shunlist.csv +20 -0
  91. data/spec/feeds/data/blocklist_de_apache-ip-reputation.txt +17 -0
  92. data/spec/feeds/data/blocklist_de_bots-ip-reputation.txt +15 -0
  93. data/spec/feeds/data/blocklist_de_ftp-ip-reputation.txt +7 -0
  94. data/spec/feeds/data/blocklist_de_imap-ip-reputation.txt +8 -0
  95. data/spec/feeds/data/blocklist_de_pop3-ip-reputation.txt +11 -0
  96. data/spec/feeds/data/blocklist_de_proftpd-ip-reputation.txt +12 -0
  97. data/spec/feeds/data/blocklist_de_sip-ip-reputation.txt +9 -0
  98. data/spec/feeds/data/blocklist_de_ssh-ip-reputation.txt +10 -0
  99. data/spec/feeds/data/blocklist_de_strongips-ip-reputation.txt +11 -0
  100. data/spec/feeds/data/ciarmy-ip-reputation.txt +11 -0
  101. data/spec/feeds/data/cruzit-ip-reputation.txt +14 -0
  102. data/spec/feeds/data/dan_me_uk_torlist-ip-reputation.txt +11 -0
  103. data/spec/feeds/data/dshield_topattackers.xml +4 -0
  104. data/spec/feeds/data/feodo_domainlist.txt +18 -0
  105. data/spec/feeds/data/feodo_iplist.txt +20 -0
  106. data/spec/feeds/data/infiltrated_iplist.txt +16 -0
  107. data/spec/feeds/data/malc0de_domainlist.txt +18 -0
  108. data/spec/feeds/data/malc0de_iplist.txt +14 -0
  109. data/spec/feeds/data/mirc_domainlist.txt +31 -0
  110. data/spec/feeds/data/nothink_irc_iplist.txt +14 -0
  111. data/spec/feeds/data/nothink_ssh_iplist.txt +10 -0
  112. data/spec/feeds/data/openbl_iplist.txt +12 -0
  113. data/spec/feeds/data/palevo_domainlist.txt +25 -0
  114. data/spec/feeds/data/palevo_iplist.txt +24 -0
  115. data/spec/feeds/data/phishtank-sample.json.gz +0 -0
  116. data/spec/feeds/data/spyeye_domainlist.txt +16 -0
  117. data/spec/feeds/data/spyeye_iplist.txt +19 -0
  118. data/spec/feeds/data/t-arend-de_ssh_iplist.txt +17 -0
  119. data/spec/feeds/data/the_haleys_ssh_iplist.txt +12 -0
  120. data/spec/feeds/data/yourcmc_ssh-ip_reputation.txt +27 -0
  121. data/spec/feeds/data/zeus-ip_reputation.txt +285 -0
  122. data/spec/feeds/data/zeus_domainlist.txt +27 -0
  123. data/spec/feeds/dshield_attackers-top1000_spec.rb +43 -0
  124. data/spec/feeds/feodo-domain_reputation_spec.rb +50 -0
  125. data/spec/feeds/feodo-ip_reputation_spec.rb +50 -0
  126. data/spec/feeds/infiltrated-ip_reputation_spec.rb +50 -0
  127. data/spec/feeds/malc0de-domain_reputation_spec.rb +50 -0
  128. data/spec/feeds/malc0de-ip_reputation_spec.rb +50 -0
  129. data/spec/feeds/mirc-domain_reputation_spec.rb +50 -0
  130. data/spec/feeds/nothink_irc-ip_reputation_spec.rb +50 -0
  131. data/spec/feeds/nothink_ssh-ip_reputation_spec.rb +50 -0
  132. data/spec/feeds/openbl-ip_reputation_spec.rb +50 -0
  133. data/spec/feeds/palevo-domain_reputation_spec.rb +50 -0
  134. data/spec/feeds/palevo-ip_reputation_spec.rb +50 -0
  135. data/spec/feeds/phishtank_spec.rb +45 -0
  136. data/spec/feeds/spyeye-domain_reputation_spec.rb +50 -0
  137. data/spec/feeds/spyeye-ip_reputation_spec.rb +50 -0
  138. data/spec/feeds/t-arend-de_ssh-ip_reputation_spec.rb +50 -0
  139. data/spec/feeds/the_haleys_ssh-ip_reputation_spec.rb +50 -0
  140. data/spec/feeds/yourcmc_ssh-ip_reputation_spec.rb +50 -0
  141. data/spec/feeds/zeus-domain_reputation_spec.rb +50 -0
  142. data/spec/feeds/zeus-ip_reputation_spec.rb +50 -0
  143. data/spec/fixtures/feed/provider1/feed1.feed +6 -0
  144. data/spec/fixtures/parsers/test.xml +13 -0
  145. data/spec/fixtures/parsers/test_self_closing.xml +20 -0
  146. data/spec/fixtures/plugins/bad/threatinator/plugins/test_error1/plugin.rb +1 -0
  147. data/spec/fixtures/plugins/bad/threatinator/plugins/test_missing1/plugin.rb +0 -0
  148. data/spec/fixtures/plugins/fake.rb +19 -0
  149. data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_a.rb +8 -0
  150. data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_b.rb +8 -0
  151. data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_c.rb +8 -0
  152. data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_d.rb +8 -0
  153. data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_e.rb +8 -0
  154. data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_f.rb +8 -0
  155. data/spec/spec_helper.rb +52 -0
  156. data/spec/support/bad_feeds/missing_fetcher.feed +7 -0
  157. data/spec/support/bad_feeds/missing_name.feed +6 -0
  158. data/spec/support/bad_feeds/missing_parser.feed +3 -0
  159. data/spec/support/bad_feeds/missing_provider.feed +5 -0
  160. data/spec/support/factories/event.rb +27 -0
  161. data/spec/support/factories/feed.rb +32 -0
  162. data/spec/support/factories/feed_builder.rb +65 -0
  163. data/spec/support/factories/feed_registry.rb +8 -0
  164. data/spec/support/factories/output.rb +11 -0
  165. data/spec/support/factories/record.rb +17 -0
  166. data/spec/support/factories/xml_node.rb +33 -0
  167. data/spec/support/helpers/io.rb +11 -0
  168. data/spec/support/helpers/models.rb +13 -0
  169. data/spec/support/shared/action_builder.rb +47 -0
  170. data/spec/support/shared/decoder.rb +70 -0
  171. data/spec/support/shared/feeds.rb +218 -0
  172. data/spec/support/shared/fetcher.rb +48 -0
  173. data/spec/support/shared/filter.rb +14 -0
  174. data/spec/support/shared/io-like.rb +7 -0
  175. data/spec/support/shared/output.rb +120 -0
  176. data/spec/support/shared/parsers.rb +51 -0
  177. data/spec/support/shared/record.rb +111 -0
  178. data/spec/threatinator/actions/list/action_spec.rb +93 -0
  179. data/spec/threatinator/actions/run/action_spec.rb +89 -0
  180. data/spec/threatinator/actions/run/config_spec.rb +39 -0
  181. data/spec/threatinator/actions/run/coverage_observer_spec.rb +116 -0
  182. data/spec/threatinator/actions/run/output_config_spec.rb +89 -0
  183. data/spec/threatinator/cli/list_action_builder_spec.rb +57 -0
  184. data/spec/threatinator/cli/run_action_builder_spec.rb +133 -0
  185. data/spec/threatinator/cli_spec.rb +175 -0
  186. data/spec/threatinator/config/base_spec.rb +39 -0
  187. data/spec/threatinator/config/feed_search_spec.rb +76 -0
  188. data/spec/threatinator/decoders/gzip_spec.rb +75 -0
  189. data/spec/threatinator/event_builder_spec.rb +33 -0
  190. data/spec/threatinator/event_spec.rb +30 -0
  191. data/spec/threatinator/feed_builder_spec.rb +636 -0
  192. data/spec/threatinator/feed_registry_spec.rb +198 -0
  193. data/spec/threatinator/feed_runner_spec.rb +155 -0
  194. data/spec/threatinator/feed_spec.rb +169 -0
  195. data/spec/threatinator/fetcher_spec.rb +12 -0
  196. data/spec/threatinator/fetchers/http_spec.rb +32 -0
  197. data/spec/threatinator/filter_spec.rb +13 -0
  198. data/spec/threatinator/filters/block_spec.rb +16 -0
  199. data/spec/threatinator/filters/comments_spec.rb +13 -0
  200. data/spec/threatinator/filters/whitespace_spec.rb +12 -0
  201. data/spec/threatinator/parser_spec.rb +13 -0
  202. data/spec/threatinator/parsers/csv/parser_spec.rb +202 -0
  203. data/spec/threatinator/parsers/getline/parser_spec.rb +83 -0
  204. data/spec/threatinator/parsers/json/parser_spec.rb +106 -0
  205. data/spec/threatinator/parsers/json/record_spec.rb +30 -0
  206. data/spec/threatinator/parsers/xml/node_spec.rb +335 -0
  207. data/spec/threatinator/parsers/xml/parser_spec.rb +263 -0
  208. data/spec/threatinator/parsers/xml/path_spec.rb +209 -0
  209. data/spec/threatinator/parsers/xml/pattern_spec.rb +72 -0
  210. data/spec/threatinator/parsers/xml/record_spec.rb +27 -0
  211. data/spec/threatinator/plugin_loader_spec.rb +238 -0
  212. data/spec/threatinator/plugins/output/csv_spec.rb +46 -0
  213. data/spec/threatinator/plugins/output/null_spec.rb +17 -0
  214. data/spec/threatinator/plugins/output/rubydebug_spec.rb +37 -0
  215. data/spec/threatinator/property_definer_spec.rb +155 -0
  216. data/spec/threatinator/record_spec.rb +19 -0
  217. data/spec/threatinator/registry_spec.rb +97 -0
  218. data/spec/threatinator/runner_spec.rb +273 -0
  219. metadata +376 -0
@@ -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
+
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/cli/list_action_builder'
3
+
4
+ describe Threatinator::CLI::ListActionBuilder do
5
+ describe 'an instance' do
6
+ let(:config_hash) { {} }
7
+ let(:extra_args) { [] }
8
+ let(:builder) { described_class.new(config_hash, extra_args) }
9
+
10
+ it_behaves_like "an action builder"
11
+
12
+ describe "#config" do
13
+ context "when config_hash['list'] is provided" do
14
+ let(:list_hash) { double('list hash') }
15
+ before :each do
16
+ config_hash['list'] = list_hash
17
+ end
18
+ it "builds a new Threatinator::Actions::List::Config using config_hash['list']" do
19
+ expect(Threatinator::Actions::List::Config).to receive(:new).with(list_hash)
20
+ builder.config
21
+ end
22
+ end
23
+ context "when config_hash['list'] does not exist" do
24
+ before :each do
25
+ config_hash.delete 'list'
26
+ end
27
+ it "builds a new Threatinator::Config::FeedSearch using an empty hash" do
28
+ expect(Threatinator::Actions::List::Config).to receive(:new).with({})
29
+ builder.config
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "#build" do
35
+ let(:action) { double('action') }
36
+ let(:config) { double('config') }
37
+ let(:feed_registry) { double('feed registry') }
38
+ before :each do
39
+ allow(Threatinator::Actions::List::Action).to receive(:new).and_return(action)
40
+ allow(builder).to receive(:config).and_return(config)
41
+ allow(builder).to receive(:feed_registry).and_return(feed_registry)
42
+ end
43
+
44
+ let(:result) { builder.build }
45
+
46
+ it "builds an instance of Threatinator::Actions::List::Action using #feed_registry and #config" do
47
+ expect(Threatinator::Actions::List::Action).to receive(:new).with(feed_registry, config)
48
+ builder.build
49
+ end
50
+
51
+ it "returns the instance of the action" do
52
+ expect(builder.build).to be(action)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+ require 'threatinator/cli/run_action_builder'
4
+ require 'threatinator/plugin_loader'
5
+
6
+ describe Threatinator::CLI::RunActionBuilder do
7
+ describe 'an instance' do
8
+ let(:plugin_loader) { Threatinator::PluginLoader.new }
9
+ let(:config_class) { Threatinator::Actions::Run::Config.generate(plugin_loader) }
10
+ let(:config_hash) { { 'run' => {} } }
11
+ let(:extra_args) { [] }
12
+ let(:builder) { described_class.new(config_hash, extra_args, config_class) }
13
+
14
+ it_behaves_like "an action builder"
15
+
16
+ describe "#config" do
17
+ let(:config) { builder.config }
18
+ it "returns an instance of config_class" do
19
+ expect(config).to be_a(config_class)
20
+ end
21
+
22
+ describe "config_hash['run']['coverage_output']" do
23
+ context "when nil" do
24
+ before :each do
25
+ config_hash['run'].delete('coverage_output')
26
+ end
27
+
28
+ it "sets config.observers to []" do
29
+ config = builder.config
30
+ expect(config.observers).to contain_exactly()
31
+ end
32
+ end
33
+
34
+ context "when set to a string" do
35
+ let(:coverage_proc) { lambda { } }
36
+ before :each do
37
+ config_hash['run']['coverage_output'] = "asdf"
38
+ end
39
+ it "initializes a CoverageObserver with the string" do
40
+ expect(Threatinator::Actions::Run::CoverageObserver).to receive(:new).with('asdf')
41
+ builder.config
42
+ end
43
+ it "sets config.observers an array consisting of the CoverageObserver" do
44
+ observer = double('observer')
45
+ expect(Threatinator::Actions::Run::CoverageObserver).to receive(:new).and_return(observer)
46
+
47
+ config = builder.config
48
+ expect(config.observers).to contain_exactly(observer)
49
+ end
50
+ end
51
+ end
52
+
53
+ context "config_hash['run']['feed_provider']" do
54
+ context "when nil" do
55
+ before :each do
56
+ config_hash['run'].delete('feed_provider')
57
+ end
58
+ context "and there are no extra arguments" do
59
+ specify "#feed_provider is nil" do
60
+ expect(config.feed_provider).to be_nil
61
+ end
62
+ end
63
+
64
+ context "and there is at least one extra argument" do
65
+ before :each do
66
+ extra_args << "arg1"
67
+ extra_args << "arg2"
68
+ extra_args << "arg3"
69
+ end
70
+ specify "#feed_provider is the first extra argument" do
71
+ expect(config.feed_provider).to eq("arg1")
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ context "config_hash['run']['feed_name']" do
78
+ context "when nil" do
79
+ before :each do
80
+ config_hash['run'].delete('feed_name')
81
+ end
82
+ context "and there are no extra arguments" do
83
+ specify "#feed_name is nil" do
84
+ expect(config.feed_name).to be_nil
85
+ end
86
+ end
87
+
88
+ context "and there are extra arguments" do
89
+ before :each do
90
+ extra_args << "arg1"
91
+ extra_args << "arg2"
92
+ extra_args << "arg3"
93
+ end
94
+
95
+ specify "#feed_name is the first extra argument if feed_provider was configured" do
96
+ config_hash['run']['feed_provider'] = "foo"
97
+ expect(config.feed_name).to eq("arg1")
98
+ end
99
+
100
+ specify "#feed_name is the second extra argument if feed_provider was not configured" do
101
+ config_hash['run'].delete('feed_provider')
102
+ expect(config.feed_name).to eq("arg2")
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "#build" do
110
+ let(:action) { double('action') }
111
+ let(:config) { double('config') }
112
+ let(:feed_registry) { double('feed registry') }
113
+ before :each do
114
+ allow(Threatinator::Actions::Run::Action).to receive(:new).and_return(action)
115
+ allow(builder).to receive(:config).and_return(config)
116
+ allow(builder).to receive(:feed_registry).and_return(feed_registry)
117
+ end
118
+
119
+ let(:result) { builder.build }
120
+
121
+ it "builds an instance of Threatinator::Actions::Run::Action using #feed_registry and #config" do
122
+ expect(Threatinator::Actions::Run::Action).to receive(:new).with(feed_registry, config)
123
+ builder.build
124
+ end
125
+
126
+ it "returns the instance of the action" do
127
+ expect(builder.build).to be(action)
128
+ end
129
+
130
+ end
131
+ end
132
+ end
133
+
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/cli'
3
+ require 'fileutils'
4
+
5
+ shared_context "threatinator commands" do
6
+ let(:action) { double('action') }
7
+ let(:builder) { double('builder') }
8
+
9
+ before :each do
10
+ allow(action_builder_class).to receive(:new).and_return(builder)
11
+ allow(builder).to receive(:build).and_return(action)
12
+ allow(action).to receive(:exec)
13
+ end
14
+
15
+ end
16
+ shared_examples_for "a threatinator command" do
17
+ context '--feed_search.path=foo/bar' do
18
+ before :each do
19
+ global_args << '--feed_search.path=foo/bar'
20
+ Threatinator::CLI.process!(args)
21
+ end
22
+
23
+ it "generates the proper config hash" do
24
+ expect(action_builder_class).to have_received(:new) do |opts, args, *extra|
25
+ expect(opts).to match(
26
+ {
27
+ 'feed_search' => {
28
+ 'exclude_default' => false,
29
+ 'path' => ['foo/bar']
30
+ }
31
+ }
32
+ )
33
+ expect(args).to eq([])
34
+ end
35
+ end
36
+ end
37
+
38
+ context '--feed_search.path=foo/bar,woof/bark' do
39
+ before :each do
40
+ global_args << '--feed_search.path=foo/bar,woof/bark'
41
+ Threatinator::CLI.process!(args)
42
+ end
43
+
44
+ it "generates the proper config hash" do
45
+ expect(action_builder_class).to have_received(:new) do |opts, args, *extra|
46
+ expect(opts).to match(
47
+ {
48
+ 'feed_search' => {
49
+ 'exclude_default' => false,
50
+ 'path' => ['foo/bar', 'woof/bark']
51
+ }
52
+ }
53
+ )
54
+ expect(args).to eq([])
55
+ end
56
+ end
57
+ end
58
+
59
+ context '--feed_search.exclude_default' do
60
+ before :each do
61
+ global_args << '--feed_search.exclude_default'
62
+ Threatinator::CLI.process!(args)
63
+ end
64
+
65
+ it "generates the proper config hash" do
66
+ expect(action_builder_class).to have_received(:new).with({
67
+ 'feed_search' => {
68
+ 'exclude_default' => true
69
+ }
70
+ }, [],
71
+ kind_of(Class)
72
+ )
73
+ end
74
+ end
75
+
76
+ context "--help" do
77
+ before :each do
78
+ global_args << '--help'
79
+ @exception = nil
80
+ @exit_code = nil
81
+
82
+ @captured_output = temp_stdout do
83
+ @exit_code = Threatinator::CLI.process!(args)
84
+ end
85
+ end
86
+
87
+ it "should have an exit code of 0" do
88
+ expect(@exit_code).to eq(0)
89
+ end
90
+
91
+ it "should print usage information" do
92
+ expect(@captured_output).to match(/^NAME/)
93
+ end
94
+
95
+ it "should not create an action builder" do
96
+ expect(action_builder_class).not_to have_received(:new)
97
+ end
98
+ end
99
+ end
100
+
101
+ describe Threatinator::CLI do
102
+ let(:global_args) { [] }
103
+ let(:command) { [] }
104
+ let(:command_args) { [] }
105
+ let(:args) { global_args + [ command ] + command_args }
106
+
107
+ describe "list command" do
108
+ let(:command) { 'list' }
109
+ let(:action) { double('action') }
110
+ let(:builder) { double('builder') }
111
+
112
+ before :each do
113
+ allow(Threatinator::CLI::ListActionBuilder).to receive(:new).and_return(builder)
114
+ allow(builder).to receive(:build).and_return(action)
115
+ allow(action).to receive(:exec)
116
+ end
117
+
118
+ it "should create a ListActionBuilder" do
119
+ Threatinator::CLI.process!(args)
120
+ expect(Threatinator::CLI::ListActionBuilder).to have_received(:new).with({"feed_search" => {"exclude_default" => false}}, [])
121
+ end
122
+
123
+ it "should build an action" do
124
+ Threatinator::CLI.process!(args)
125
+ expect(builder).to have_received(:build)
126
+ end
127
+
128
+ it "should execute a list action" do
129
+ Threatinator::CLI.process!(args)
130
+ expect(action).to have_received(:exec)
131
+ end
132
+ end
133
+
134
+ describe "run" do
135
+ let(:action_builder_class) { Threatinator::CLI::RunActionBuilder }
136
+ let(:command) { 'run' }
137
+ include_context "threatinator commands"
138
+
139
+ context "with no additional arguments" do
140
+ it "should create an action builder with no config or args" do
141
+ Threatinator::CLI.process!(args)
142
+ expect(action_builder_class).to have_received(:new).with(
143
+ {
144
+ "feed_search" => {
145
+ "exclude_default" => false
146
+ }
147
+ }, [], kind_of(Class))
148
+ end
149
+ end
150
+
151
+ context "feed_provider feed_name" do
152
+ before :each do
153
+ command_args << 'feed_provider'
154
+ command_args << 'feed_name'
155
+ end
156
+ it "should create an action builder with args feed_provider feed_name" do
157
+ Threatinator::CLI.process!(args)
158
+ expect(action_builder_class).to have_received(:new).with(
159
+ {
160
+ "feed_search" => {
161
+ "exclude_default" => false
162
+ },
163
+ "run" => {
164
+ "feed_provider" => "feed_provider",
165
+ "feed_name" => "feed_name"
166
+ }
167
+ }, [], kind_of(Class)
168
+ )
169
+ end
170
+ end
171
+
172
+ it_should_behave_like "a threatinator command"
173
+ end
174
+ end
175
+