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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/CONTRIBUTING.md +119 -0
- data/Gemfile +28 -0
- data/LICENSE +165 -0
- data/README.md +45 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/threatinator +5 -0
- data/lib/threatinator.rb +3 -0
- data/lib/threatinator/action.rb +14 -0
- data/lib/threatinator/actions/list.rb +2 -0
- data/lib/threatinator/actions/list/action.rb +53 -0
- data/lib/threatinator/actions/list/config.rb +10 -0
- data/lib/threatinator/actions/run.rb +2 -0
- data/lib/threatinator/actions/run/action.rb +45 -0
- data/lib/threatinator/actions/run/config.rb +32 -0
- data/lib/threatinator/actions/run/coverage_observer.rb +54 -0
- data/lib/threatinator/actions/run/output_config.rb +59 -0
- data/lib/threatinator/cli.rb +13 -0
- data/lib/threatinator/cli/action_builder.rb +33 -0
- data/lib/threatinator/cli/list_action_builder.rb +19 -0
- data/lib/threatinator/cli/parser.rb +113 -0
- data/lib/threatinator/cli/run_action_builder.rb +41 -0
- data/lib/threatinator/config.rb +6 -0
- data/lib/threatinator/config/base.rb +35 -0
- data/lib/threatinator/config/feed_search.rb +25 -0
- data/lib/threatinator/decoder.rb +24 -0
- data/lib/threatinator/decoders/gzip.rb +30 -0
- data/lib/threatinator/event.rb +27 -0
- data/lib/threatinator/event_builder.rb +41 -0
- data/lib/threatinator/exceptions.rb +61 -0
- data/lib/threatinator/feed.rb +82 -0
- data/lib/threatinator/feed_builder.rb +156 -0
- data/lib/threatinator/feed_registry.rb +47 -0
- data/lib/threatinator/feed_runner.rb +118 -0
- data/lib/threatinator/fetcher.rb +22 -0
- data/lib/threatinator/fetchers/http.rb +46 -0
- data/lib/threatinator/filter.rb +12 -0
- data/lib/threatinator/filters/block.rb +18 -0
- data/lib/threatinator/filters/comments.rb +16 -0
- data/lib/threatinator/filters/whitespace.rb +19 -0
- data/lib/threatinator/output.rb +50 -0
- data/lib/threatinator/parser.rb +23 -0
- data/lib/threatinator/parsers/csv.rb +7 -0
- data/lib/threatinator/parsers/csv/parser.rb +77 -0
- data/lib/threatinator/parsers/getline.rb +8 -0
- data/lib/threatinator/parsers/getline/parser.rb +45 -0
- data/lib/threatinator/parsers/json.rb +8 -0
- data/lib/threatinator/parsers/json/adapters/oj.rb +65 -0
- data/lib/threatinator/parsers/json/parser.rb +45 -0
- data/lib/threatinator/parsers/json/record.rb +20 -0
- data/lib/threatinator/parsers/xml.rb +8 -0
- data/lib/threatinator/parsers/xml/node.rb +79 -0
- data/lib/threatinator/parsers/xml/node_builder.rb +39 -0
- data/lib/threatinator/parsers/xml/parser.rb +44 -0
- data/lib/threatinator/parsers/xml/path.rb +70 -0
- data/lib/threatinator/parsers/xml/pattern.rb +53 -0
- data/lib/threatinator/parsers/xml/record.rb +14 -0
- data/lib/threatinator/parsers/xml/sax_document.rb +64 -0
- data/lib/threatinator/plugin_loader.rb +115 -0
- data/lib/threatinator/plugins/output/csv.rb +47 -0
- data/lib/threatinator/plugins/output/null.rb +17 -0
- data/lib/threatinator/plugins/output/rubydebug.rb +16 -0
- data/lib/threatinator/property_definer.rb +101 -0
- data/lib/threatinator/record.rb +22 -0
- data/lib/threatinator/registry.rb +53 -0
- data/lib/threatinator/util.rb +15 -0
- data/spec/feeds/ET_compromised-ip_reputation_spec.rb +50 -0
- data/spec/feeds/alienvault-ip_reputation_spec.rb +50 -0
- data/spec/feeds/arbor_fastflux-domain_reputation_spec.rb +50 -0
- data/spec/feeds/arbor_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/autoshun_shunlist_spec.rb +42 -0
- data/spec/feeds/blocklist_de_apache-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_bots-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_ftp-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_imap-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_pop3-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_proftpd-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_sip-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_strongips-ip_reputation_spec.rb +50 -0
- data/spec/feeds/ciarmy-ip_reputation_spec.rb +50 -0
- data/spec/feeds/cruzit-ip_reputation_spec.rb +50 -0
- data/spec/feeds/dan_me_uk_torlist-ip_reputation_spec.rb +50 -0
- data/spec/feeds/data/ET_compromised-ip_reputation.txt +11 -0
- data/spec/feeds/data/alienvault-ip_reputation.txt +18 -0
- data/spec/feeds/data/arbor_domainlist.txt +11 -0
- data/spec/feeds/data/arbor_ssh.txt +16 -0
- data/spec/feeds/data/autoshun_shunlist.csv +20 -0
- data/spec/feeds/data/blocklist_de_apache-ip-reputation.txt +17 -0
- data/spec/feeds/data/blocklist_de_bots-ip-reputation.txt +15 -0
- data/spec/feeds/data/blocklist_de_ftp-ip-reputation.txt +7 -0
- data/spec/feeds/data/blocklist_de_imap-ip-reputation.txt +8 -0
- data/spec/feeds/data/blocklist_de_pop3-ip-reputation.txt +11 -0
- data/spec/feeds/data/blocklist_de_proftpd-ip-reputation.txt +12 -0
- data/spec/feeds/data/blocklist_de_sip-ip-reputation.txt +9 -0
- data/spec/feeds/data/blocklist_de_ssh-ip-reputation.txt +10 -0
- data/spec/feeds/data/blocklist_de_strongips-ip-reputation.txt +11 -0
- data/spec/feeds/data/ciarmy-ip-reputation.txt +11 -0
- data/spec/feeds/data/cruzit-ip-reputation.txt +14 -0
- data/spec/feeds/data/dan_me_uk_torlist-ip-reputation.txt +11 -0
- data/spec/feeds/data/dshield_topattackers.xml +4 -0
- data/spec/feeds/data/feodo_domainlist.txt +18 -0
- data/spec/feeds/data/feodo_iplist.txt +20 -0
- data/spec/feeds/data/infiltrated_iplist.txt +16 -0
- data/spec/feeds/data/malc0de_domainlist.txt +18 -0
- data/spec/feeds/data/malc0de_iplist.txt +14 -0
- data/spec/feeds/data/mirc_domainlist.txt +31 -0
- data/spec/feeds/data/nothink_irc_iplist.txt +14 -0
- data/spec/feeds/data/nothink_ssh_iplist.txt +10 -0
- data/spec/feeds/data/openbl_iplist.txt +12 -0
- data/spec/feeds/data/palevo_domainlist.txt +25 -0
- data/spec/feeds/data/palevo_iplist.txt +24 -0
- data/spec/feeds/data/phishtank-sample.json.gz +0 -0
- data/spec/feeds/data/spyeye_domainlist.txt +16 -0
- data/spec/feeds/data/spyeye_iplist.txt +19 -0
- data/spec/feeds/data/t-arend-de_ssh_iplist.txt +17 -0
- data/spec/feeds/data/the_haleys_ssh_iplist.txt +12 -0
- data/spec/feeds/data/yourcmc_ssh-ip_reputation.txt +27 -0
- data/spec/feeds/data/zeus-ip_reputation.txt +285 -0
- data/spec/feeds/data/zeus_domainlist.txt +27 -0
- data/spec/feeds/dshield_attackers-top1000_spec.rb +43 -0
- data/spec/feeds/feodo-domain_reputation_spec.rb +50 -0
- data/spec/feeds/feodo-ip_reputation_spec.rb +50 -0
- data/spec/feeds/infiltrated-ip_reputation_spec.rb +50 -0
- data/spec/feeds/malc0de-domain_reputation_spec.rb +50 -0
- data/spec/feeds/malc0de-ip_reputation_spec.rb +50 -0
- data/spec/feeds/mirc-domain_reputation_spec.rb +50 -0
- data/spec/feeds/nothink_irc-ip_reputation_spec.rb +50 -0
- data/spec/feeds/nothink_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/openbl-ip_reputation_spec.rb +50 -0
- data/spec/feeds/palevo-domain_reputation_spec.rb +50 -0
- data/spec/feeds/palevo-ip_reputation_spec.rb +50 -0
- data/spec/feeds/phishtank_spec.rb +45 -0
- data/spec/feeds/spyeye-domain_reputation_spec.rb +50 -0
- data/spec/feeds/spyeye-ip_reputation_spec.rb +50 -0
- data/spec/feeds/t-arend-de_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/the_haleys_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/yourcmc_ssh-ip_reputation_spec.rb +50 -0
- data/spec/feeds/zeus-domain_reputation_spec.rb +50 -0
- data/spec/feeds/zeus-ip_reputation_spec.rb +50 -0
- data/spec/fixtures/feed/provider1/feed1.feed +6 -0
- data/spec/fixtures/parsers/test.xml +13 -0
- data/spec/fixtures/parsers/test_self_closing.xml +20 -0
- data/spec/fixtures/plugins/bad/threatinator/plugins/test_error1/plugin.rb +1 -0
- data/spec/fixtures/plugins/bad/threatinator/plugins/test_missing1/plugin.rb +0 -0
- data/spec/fixtures/plugins/fake.rb +19 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_a.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type1/plugin_b.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_c.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type2/plugin_d.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_e.rb +8 -0
- data/spec/fixtures/plugins/good/threatinator/plugins/test_type3/plugin_f.rb +8 -0
- data/spec/spec_helper.rb +52 -0
- data/spec/support/bad_feeds/missing_fetcher.feed +7 -0
- data/spec/support/bad_feeds/missing_name.feed +6 -0
- data/spec/support/bad_feeds/missing_parser.feed +3 -0
- data/spec/support/bad_feeds/missing_provider.feed +5 -0
- data/spec/support/factories/event.rb +27 -0
- data/spec/support/factories/feed.rb +32 -0
- data/spec/support/factories/feed_builder.rb +65 -0
- data/spec/support/factories/feed_registry.rb +8 -0
- data/spec/support/factories/output.rb +11 -0
- data/spec/support/factories/record.rb +17 -0
- data/spec/support/factories/xml_node.rb +33 -0
- data/spec/support/helpers/io.rb +11 -0
- data/spec/support/helpers/models.rb +13 -0
- data/spec/support/shared/action_builder.rb +47 -0
- data/spec/support/shared/decoder.rb +70 -0
- data/spec/support/shared/feeds.rb +218 -0
- data/spec/support/shared/fetcher.rb +48 -0
- data/spec/support/shared/filter.rb +14 -0
- data/spec/support/shared/io-like.rb +7 -0
- data/spec/support/shared/output.rb +120 -0
- data/spec/support/shared/parsers.rb +51 -0
- data/spec/support/shared/record.rb +111 -0
- data/spec/threatinator/actions/list/action_spec.rb +93 -0
- data/spec/threatinator/actions/run/action_spec.rb +89 -0
- data/spec/threatinator/actions/run/config_spec.rb +39 -0
- data/spec/threatinator/actions/run/coverage_observer_spec.rb +116 -0
- data/spec/threatinator/actions/run/output_config_spec.rb +89 -0
- data/spec/threatinator/cli/list_action_builder_spec.rb +57 -0
- data/spec/threatinator/cli/run_action_builder_spec.rb +133 -0
- data/spec/threatinator/cli_spec.rb +175 -0
- data/spec/threatinator/config/base_spec.rb +39 -0
- data/spec/threatinator/config/feed_search_spec.rb +76 -0
- data/spec/threatinator/decoders/gzip_spec.rb +75 -0
- data/spec/threatinator/event_builder_spec.rb +33 -0
- data/spec/threatinator/event_spec.rb +30 -0
- data/spec/threatinator/feed_builder_spec.rb +636 -0
- data/spec/threatinator/feed_registry_spec.rb +198 -0
- data/spec/threatinator/feed_runner_spec.rb +155 -0
- data/spec/threatinator/feed_spec.rb +169 -0
- data/spec/threatinator/fetcher_spec.rb +12 -0
- data/spec/threatinator/fetchers/http_spec.rb +32 -0
- data/spec/threatinator/filter_spec.rb +13 -0
- data/spec/threatinator/filters/block_spec.rb +16 -0
- data/spec/threatinator/filters/comments_spec.rb +13 -0
- data/spec/threatinator/filters/whitespace_spec.rb +12 -0
- data/spec/threatinator/parser_spec.rb +13 -0
- data/spec/threatinator/parsers/csv/parser_spec.rb +202 -0
- data/spec/threatinator/parsers/getline/parser_spec.rb +83 -0
- data/spec/threatinator/parsers/json/parser_spec.rb +106 -0
- data/spec/threatinator/parsers/json/record_spec.rb +30 -0
- data/spec/threatinator/parsers/xml/node_spec.rb +335 -0
- data/spec/threatinator/parsers/xml/parser_spec.rb +263 -0
- data/spec/threatinator/parsers/xml/path_spec.rb +209 -0
- data/spec/threatinator/parsers/xml/pattern_spec.rb +72 -0
- data/spec/threatinator/parsers/xml/record_spec.rb +27 -0
- data/spec/threatinator/plugin_loader_spec.rb +238 -0
- data/spec/threatinator/plugins/output/csv_spec.rb +46 -0
- data/spec/threatinator/plugins/output/null_spec.rb +17 -0
- data/spec/threatinator/plugins/output/rubydebug_spec.rb +37 -0
- data/spec/threatinator/property_definer_spec.rb +155 -0
- data/spec/threatinator/record_spec.rb +19 -0
- data/spec/threatinator/registry_spec.rb +97 -0
- data/spec/threatinator/runner_spec.rb +273 -0
- 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
|