threatinator 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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,209 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/parsers/xml/path'
3
+
4
+ describe Threatinator::Parsers::XML::Path do
5
+
6
+ describe 'initializing' do
7
+ context "with str_or_parts not set" do
8
+ let (:path) { described_class.new() }
9
+ describe "#parts" do
10
+ specify "returns an empty array" do
11
+ expect(path.parts).to eq([])
12
+ end
13
+ end
14
+ end
15
+
16
+ context "with str_or_parts set to a String" do
17
+ let (:path) { described_class.new('/a/b/c') }
18
+ describe "#parts" do
19
+ specify "returns the string split by '/'" do
20
+ expect(path.parts).to eq(['a', 'b', 'c'])
21
+ end
22
+ end
23
+ it "raises ArgumentError when the string doesn't begin with '/'" do
24
+ expect {
25
+ described_class.new("a/b/c")
26
+ }.to raise_error(ArgumentError)
27
+ end
28
+ it "raises ArgumentError when the string is empty" do
29
+ expect {
30
+ described_class.new("")
31
+ }.to raise_error(ArgumentError)
32
+ end
33
+ end
34
+
35
+ context "with str_or_parts set to nil" do
36
+ let (:path) { described_class.new(nil) }
37
+ describe "#parts" do
38
+ specify "returns an empty array" do
39
+ expect(path.parts).to eq([])
40
+ end
41
+ end
42
+ end
43
+
44
+ context "with str_or_parts set to an array" do
45
+ let(:array) { ['a', 'b', 'c'] }
46
+ let(:path) { described_class.new(array) }
47
+ describe "#parts" do
48
+ specify "returns an array that =='s the original array" do
49
+ expect(path.parts).to eq(array)
50
+ end
51
+ specify "returns a different array instance than the original array" do
52
+ expect(path.parts).not_to equal(array)
53
+ end
54
+ end
55
+ end
56
+
57
+ it "raises TypeError when path_or_str is set to something other than a String, Array, or nil" do
58
+ expect {
59
+ described_class.new(1234)
60
+ }.to raise_error(TypeError)
61
+ end
62
+ end
63
+
64
+ describe "#==" do
65
+ it "returns true when testing against itself" do
66
+ path = described_class.new('/a/b/c')
67
+ expect(path).to be == path
68
+ end
69
+ it "returns true when testing another path with the same parts" do
70
+ path = described_class.new('/a/b/c')
71
+ path2 = described_class.new(['a', 'b', 'c'])
72
+ expect(path).to be == path2
73
+ end
74
+ it "returns true when testing an object that responds to #parts with the same values" do
75
+ path = described_class.new('/a/b/c')
76
+ object = Class.new do
77
+ def parts
78
+ ['a', 'b', 'c']
79
+ end
80
+ end.new
81
+ expect(path).to be == object
82
+ end
83
+ it "returns false when testing an object that responds to #parts with different values" do
84
+ path = described_class.new('/a/b/c')
85
+ object = Class.new do
86
+ def parts
87
+ ['a', 'b', 'c', 'd']
88
+ end
89
+ end.new
90
+ expect(path).not_to be == object
91
+ end
92
+ it "returns false when testing against another path with different parts" do
93
+ path = described_class.new('/a/b/c')
94
+ path2 = described_class.new('/a/b/c/e')
95
+ expect(path).not_to be == path2
96
+ end
97
+ end
98
+
99
+ describe "#eql?" do
100
+ it "returns true when testing against itself" do
101
+ path = described_class.new('/a/b/c')
102
+ expect(path).to eql path
103
+ end
104
+ it "returns true when testing another path with the same parts" do
105
+ path = described_class.new('/a/b/c')
106
+ path2 = described_class.new(['a', 'b', 'c'])
107
+ expect(path).to eql path2
108
+ end
109
+ it "returns false when testing against another path with different parts" do
110
+ path = described_class.new('/a/b/c')
111
+ path2 = described_class.new('/a/b/c/e')
112
+ expect(path).not_to eql path2
113
+ end
114
+ it "returns false when testing an object that responds to #parts with the same values" do
115
+ path = described_class.new('/a/b/c')
116
+ object = Class.new do
117
+ def parts
118
+ ['a', 'b', 'c']
119
+ end
120
+ end.new
121
+ expect(path).not_to eql object
122
+ end
123
+ it "returns false when testing against something that is not a Path" do
124
+ path = described_class.new('/a/b/c')
125
+ path2 = "hi there"
126
+ expect(path).not_to eql path2
127
+ end
128
+ end
129
+
130
+ describe "#end_with?" do
131
+ let(:path) { described_class.new('/a/b/c') }
132
+
133
+ it "returns true when testing against itself" do
134
+ expect(path.end_with?(path)).to eq(true)
135
+ end
136
+ it "returns true when testing against an identical path" do
137
+ path2 = described_class.new('/a/b/c')
138
+ expect(path.end_with?(path2)).to eq(true)
139
+ end
140
+
141
+ it "returns true when tested against any path that it happens to end with" do
142
+ expect(path.end_with?(described_class.new('/b/c'))).to eq(true)
143
+ expect(path.end_with?(described_class.new('/c'))).to eq(true)
144
+ end
145
+
146
+ it "returns true when tested against a path with no length" do
147
+ expect(path.end_with?(described_class.new('/'))).to eq(true)
148
+ end
149
+
150
+ it "returns false when tested against a path that is longer than itself" do
151
+ expect(path.end_with?(described_class.new('/a/a/b/c'))).to eq(false)
152
+ end
153
+
154
+ it "returns false when tested against a path it does not end with" do
155
+ expect(path.end_with?(described_class.new('/a'))).to eq(false)
156
+ expect(path.end_with?(described_class.new('/a/b'))).to eq(false)
157
+ expect(path.end_with?(described_class.new('/b'))).to eq(false)
158
+ end
159
+ end
160
+
161
+ describe "#push" do
162
+ let(:path) { described_class.new }
163
+ it "adds a new entry to the end of the #parts" do
164
+ path.push('a')
165
+ expect(path.parts).to eq(['a'])
166
+ path.push('b')
167
+ expect(path.parts).to eq(['a', 'b'])
168
+ path.push('c')
169
+ expect(path.parts).to eq(['a', 'b', 'c'])
170
+ end
171
+ end
172
+
173
+ describe "#pop" do
174
+ let(:path) { described_class.new('/a/b/c') }
175
+ it "appends a new entry to the end of the #parts" do
176
+ expect(path.parts).to eq(['a', 'b', 'c'])
177
+ path.pop()
178
+ expect(path.parts).to eq(['a', 'b'])
179
+ path.pop()
180
+ expect(path.parts).to eq(['a'])
181
+ path.pop()
182
+ expect(path.parts).to eq([])
183
+ end
184
+
185
+ it "returns the value popped off the end of the parts" do
186
+ expect(path.pop()).to eq('c')
187
+ expect(path.pop()).to eq('b')
188
+ expect(path.pop()).to eq('a')
189
+ end
190
+
191
+ it "returns nil if there are no parts" do
192
+ path.pop(); path.pop(); path.pop();
193
+ expect(path.pop()).to be_nil
194
+ end
195
+ end
196
+
197
+ describe "#length" do
198
+ let(:path) { described_class.new('/a/b/c') }
199
+ it "returns the number of parts" do
200
+ expect(path.length).to eq(3)
201
+ 10.times { path.push('Z') }
202
+ expect(path.length).to eq(13)
203
+ 20.times { path.pop() }
204
+ expect(path.length).to eq(0)
205
+ end
206
+ end
207
+ end
208
+
209
+
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/parsers/xml/pattern'
3
+
4
+ describe Threatinator::Parsers::XML::Pattern do
5
+
6
+ context "when initialized with" do
7
+ let(:pattern) { described_class.new(pathspec) }
8
+
9
+ context "pathspec: '/a/b/c'" do
10
+ let(:pathspec) { '/a/b/c' }
11
+ describe "#max_depth" do
12
+ it "returns 3" do
13
+ expect(pattern.max_depth).to eq(3)
14
+ end
15
+ end
16
+ describe "#match?" do
17
+ it "returns true for the path '/a/b/c'" do
18
+ path = Threatinator::Parsers::XML::Path.new('/a/b/c')
19
+ expect(pattern.match?(path)).to eq(true)
20
+ end
21
+ it "returns false for the path '/a/b/c/d'" do
22
+ path = Threatinator::Parsers::XML::Path.new('/a/b/c/d')
23
+ expect(pattern.match?(path)).to eq(false)
24
+ end
25
+ it "returns false for the path '/a/b/cd'" do
26
+ path = Threatinator::Parsers::XML::Path.new('/a/b/cd')
27
+ expect(pattern.match?(path)).to eq(false)
28
+ end
29
+ it "returns false for the path '/a/b'" do
30
+ path = Threatinator::Parsers::XML::Path.new('/a/b')
31
+ expect(pattern.match?(path)).to eq(false)
32
+ end
33
+ end
34
+ end
35
+
36
+ context "pathspec: '//b/c'" do
37
+ let(:pathspec) { '//b/c' }
38
+ describe "#max_depth" do
39
+ it "returns Infinity" do
40
+ expect(pattern.max_depth).to eq(Float::INFINITY)
41
+ end
42
+ end
43
+ describe "#match?" do
44
+ it "returns true for the path '/a/b/c'" do
45
+ path = Threatinator::Parsers::XML::Path.new('/a/b/c')
46
+ expect(pattern.match?(path)).to eq(true)
47
+ end
48
+ it "returns true for the path '/b/c'" do
49
+ path = Threatinator::Parsers::XML::Path.new('/b/c')
50
+ expect(pattern.match?(path)).to eq(true)
51
+ end
52
+ it "returns true for the path '/a/a/a/a/a/a/a/a/b/c'" do
53
+ path = Threatinator::Parsers::XML::Path.new('/a/a/a/a/a/a/a/a/b/c')
54
+ expect(pattern.match?(path)).to eq(true)
55
+ end
56
+ it "returns false for the path '/a/b'" do
57
+ path = Threatinator::Parsers::XML::Path.new('/a/b')
58
+ expect(pattern.match?(path)).to eq(false)
59
+ end
60
+ end
61
+ end
62
+
63
+ context "pathspec: '///c'" do
64
+ let(:pathspec) { '///c' }
65
+ it "should raise an ArgumentError" do
66
+ expect {
67
+ pattern
68
+ }.to raise_error(ArgumentError)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/parsers/xml/record'
3
+
4
+ describe Threatinator::Parsers::XML::Record do
5
+ it_should_behave_like 'a record' do
6
+ let(:data) {
7
+ Threatinator::Parsers::XML::Node.new('foo', text: 'bar')
8
+ }
9
+ let(:opts) { { } }
10
+ end
11
+
12
+ context "two instances with different data" do
13
+ it_should_behave_like 'a record when compared to a differently configured record' do
14
+ let(:data) {
15
+ Threatinator::Parsers::XML::Node.new('foo', text: 'bar')
16
+ }
17
+ let(:opts) { { } }
18
+
19
+ let(:data2) {
20
+ Threatinator::Parsers::XML::Node.new('foo', text: 'bar2')
21
+ }
22
+ let(:opts2) { {} }
23
+ end
24
+ end
25
+ end
26
+
27
+
@@ -0,0 +1,238 @@
1
+ require 'spec_helper'
2
+ require 'threatinator/plugin_loader'
3
+
4
+ shared_context "good test plugins" do
5
+ before :all do
6
+ @good_plugin_path = PLUGIN_FIXTURES.join("good").to_s
7
+ $:.unshift @good_plugin_path
8
+ end
9
+
10
+ after :all do
11
+ $:.delete_if {|x| x == @good_plugin_path}
12
+ end
13
+ end
14
+
15
+ shared_context "bad test plugins" do
16
+ before :all do
17
+ @bad_plugin_path = PLUGIN_FIXTURES.join("bad").to_s
18
+ $:.unshift @bad_plugin_path
19
+ end
20
+
21
+ after :all do
22
+ $:.delete_if {|x| x == @bad_plugin_path}
23
+ end
24
+ end
25
+
26
+ describe Threatinator::PluginLoader do
27
+ include_context "good test plugins"
28
+
29
+ let(:loader) { described_class.new }
30
+
31
+ describe "#load_all_plugins" do
32
+ it "returns itself" do
33
+ expect(loader.load_all_plugins).to be(loader)
34
+ end
35
+
36
+ it "loads all plugins found in the $LOAD_PATH" do
37
+ loader.load_all_plugins
38
+ expect(loader.each(:test_type1).map {|*args| args }).to contain_exactly(
39
+ [:test_type1, :plugin_a, Threatinator::Plugins::TestType1::PluginA],
40
+ [:test_type1, :plugin_b, Threatinator::Plugins::TestType1::PluginB])
41
+ expect(loader.each(:test_type2).map {|*args| args }).to contain_exactly(
42
+ [:test_type2, :plugin_c, Threatinator::Plugins::TestType2::PluginC],
43
+ [:test_type2, :plugin_d, Threatinator::Plugins::TestType2::PluginD])
44
+ expect(loader.each(:test_type3).map {|*args| args }).to contain_exactly(
45
+ [:test_type3, :plugin_e, Threatinator::Plugins::TestType3::PluginE],
46
+ [:test_type3, :plugin_f, Threatinator::Plugins::TestType3::PluginF])
47
+ end
48
+ end
49
+
50
+ describe "#load_plugins" do
51
+ it "returns itself" do
52
+ expect(loader.load_plugins(:test_type1)).to be(loader)
53
+ end
54
+
55
+ it "loads all plugins found in the $LOAD_PATH that are of the specified type" do
56
+ expect { |b| loader.each(:test_type1, &b) }.not_to yield_control
57
+ expect { |b| loader.each(:test_type2, &b) }.not_to yield_control
58
+ expect { |b| loader.each(:test_type3, &b) }.not_to yield_control
59
+
60
+ loader.load_plugins(:test_type1)
61
+ expect(loader.each(:test_type1).map {|*args| args }).to contain_exactly(
62
+ [:test_type1, :plugin_a, Threatinator::Plugins::TestType1::PluginA],
63
+ [:test_type1, :plugin_b, Threatinator::Plugins::TestType1::PluginB])
64
+
65
+ expect { |b| loader.each(:test_type2, &b) }.not_to yield_control
66
+ expect { |b| loader.each(:test_type3, &b) }.not_to yield_control
67
+
68
+
69
+ loader.load_plugins(:test_type2)
70
+ expect(loader.each(:test_type1).map {|*args| args }).to contain_exactly(
71
+ [:test_type1, :plugin_a, Threatinator::Plugins::TestType1::PluginA],
72
+ [:test_type1, :plugin_b, Threatinator::Plugins::TestType1::PluginB])
73
+ expect(loader.each(:test_type2).map {|*args| args }).to contain_exactly(
74
+ [:test_type2, :plugin_c, Threatinator::Plugins::TestType2::PluginC],
75
+ [:test_type2, :plugin_d, Threatinator::Plugins::TestType2::PluginD])
76
+ expect { |b| loader.each(:test_type3, &b) }.not_to yield_control
77
+
78
+
79
+ loader.load_plugins(:test_type3)
80
+ expect(loader.each(:test_type1).map {|*args| args }).to contain_exactly(
81
+ [:test_type1, :plugin_a, Threatinator::Plugins::TestType1::PluginA],
82
+ [:test_type1, :plugin_b, Threatinator::Plugins::TestType1::PluginB])
83
+ expect(loader.each(:test_type2).map {|*args| args }).to contain_exactly(
84
+ [:test_type2, :plugin_c, Threatinator::Plugins::TestType2::PluginC],
85
+ [:test_type2, :plugin_d, Threatinator::Plugins::TestType2::PluginD])
86
+ expect(loader.each(:test_type3).map {|*args| args }).to contain_exactly(
87
+ [:test_type3, :plugin_e, Threatinator::Plugins::TestType3::PluginE],
88
+ [:test_type3, :plugin_f, Threatinator::Plugins::TestType3::PluginF])
89
+ end
90
+
91
+ context "when loading a plugin raises an exception" do
92
+ include_context "bad test plugins"
93
+ it "raises that error upward" do
94
+ expect {
95
+ loader.load_plugins(:test_error1)
96
+ }.to raise_error()
97
+ end
98
+ end
99
+
100
+ context "when a plugin class cannot be found" do
101
+ include_context "bad test plugins"
102
+ it "raises a PluginLoadError" do
103
+ expect {
104
+ loader.load_plugins(:test_missing1)
105
+ }.to raise_error(Threatinator::Exceptions::PluginLoadError)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#split_file_name" do
111
+ it "returns nil if the file name is not formed like 'threatinator/plugins/<type>/<name>.rb'" do
112
+
113
+ expect(loader.send(:split_file_name, File.join("foobar", "threatinator", "plugins", "type", "bla", "name.rb"))).to be_nil
114
+ expect(loader.send(:split_file_name, File.join("plugins", "type", "name.rb"))).to be_nil
115
+ expect(loader.send(:split_file_name, File.join("type", "name.rb"))).to be_nil
116
+ expect(loader.send(:split_file_name, "name.rb")).to be_nil
117
+
118
+ end
119
+
120
+ it "returns an array of the requirable path, plugin type, and plugin name" do
121
+
122
+ file_name = File.join("foobar", "threatinator", "plugins", "type", "name.rb")
123
+ expect(loader.send(:split_file_name, file_name)).to eq(['threatinator/plugins/type/name', 'type', 'name'])
124
+ end
125
+
126
+ FILE_NAME1 = File.join("threatinator", "plugins", "some_type", "some_name.rb")
127
+ FILE_NAME2 = File.join("foo", "bar", "lib", "threatinator", "plugins", "some_type", "some_name.rb")
128
+
129
+ shared_examples_for "simple split_file_name example" do
130
+ it { should eq([File.join("threatinator", "plugins", "some_type", "some_name"), "some_type", "some_name"]) }
131
+ end
132
+ describe "the return of split_file_name('#{FILE_NAME1}')" do
133
+ subject { loader.send(:split_file_name, FILE_NAME1) }
134
+ include_examples "simple split_file_name example"
135
+ end
136
+
137
+ describe "the return of split_file_name('#{FILE_NAME2}')" do
138
+ subject { loader.send(:split_file_name, FILE_NAME2) }
139
+ include_examples "simple split_file_name example"
140
+ end
141
+ end
142
+
143
+ describe "#types" do
144
+ context "when no plugins have been loaded" do
145
+ it "returns an empty array" do
146
+ expect(loader.types).to eq([])
147
+ end
148
+ end
149
+
150
+ context "when some plugins have been loaded" do
151
+ it "returns an array of type names (in symbol form)" do
152
+ loader.load_plugins(:test_type1)
153
+ loader.load_plugins(:test_type2)
154
+ loader.load_plugins(:test_type3)
155
+ expect(loader.types).to match_array([:test_type1, :test_type2, :test_type3])
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "#get(type, name)" do
161
+ context "when there are no plugins for the specified type" do
162
+ it "returns nil" do
163
+ expect(loader.get(:test_type1, :name)).to be_nil
164
+ end
165
+ end
166
+
167
+ context "when there are plugins for the specified type" do
168
+ context "when a plugin does not exist for the specified name" do
169
+ it "returns nil" do
170
+ loader.load_plugins(:test_type1)
171
+ expect(loader.get(:test_type1, :foobar)).to be_nil
172
+ end
173
+ end
174
+
175
+ context "when a plugin does exist for the specified name" do
176
+ it "returns the plugin" do
177
+ loader.load_plugins(:test_type1)
178
+ expect(loader.get(:test_type1, :plugin_a)).to eq(Threatinator::Plugins::TestType1::PluginA)
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ describe "#each" do
185
+ context "when there are no plugins loaded" do
186
+ it "doesn't yield anything" do
187
+ expect { |b|
188
+ loader.each(&b)
189
+ }.not_to yield_control
190
+ end
191
+ end
192
+
193
+ context "when there plugins loaded" do
194
+ it "yields the type, name, and plugin for all plugins" do
195
+ loader.load_plugins(:test_type1)
196
+ loader.load_plugins(:test_type2)
197
+ loader.load_plugins(:test_type3)
198
+
199
+ data = []
200
+ loader.each do |type, name, plugin|
201
+ data << [type, name, plugin]
202
+ end
203
+ expect(data).to contain_exactly(
204
+ [:test_type1, :plugin_a, Threatinator::Plugins::TestType1::PluginA],
205
+ [:test_type1, :plugin_b, Threatinator::Plugins::TestType1::PluginB],
206
+ [:test_type2, :plugin_c, Threatinator::Plugins::TestType2::PluginC],
207
+ [:test_type2, :plugin_d, Threatinator::Plugins::TestType2::PluginD],
208
+ [:test_type3, :plugin_e, Threatinator::Plugins::TestType3::PluginE],
209
+ [:test_type3, :plugin_f, Threatinator::Plugins::TestType3::PluginF]
210
+ )
211
+ end
212
+ end
213
+ end
214
+
215
+ describe "#each(type)" do
216
+ context "when there are no plugins for the specified type" do
217
+ it "doesn't yield anything" do
218
+ expect { |b|
219
+ loader.each(:foobar, &b)
220
+ }.not_to yield_control
221
+ end
222
+ end
223
+
224
+ context "when there are plugins for the specified type" do
225
+ it "yields the type, name, and plugin for each plugin of the specified type" do
226
+ loader.load_plugins(:test_type1)
227
+ data = []
228
+ loader.each(:test_type1) do |type, name, plugin|
229
+ data << [type, name, plugin]
230
+ end
231
+ expect(data).to contain_exactly(
232
+ [ :test_type1, :plugin_a, Threatinator::Plugins::TestType1::PluginA],
233
+ [ :test_type1, :plugin_b, Threatinator::Plugins::TestType1::PluginB]
234
+ )
235
+ end
236
+ end
237
+ end
238
+ end