threatinator 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -2
- data/Gemfile +18 -13
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/feeds/ET_block-ip_reputation.feed +26 -0
- data/feeds/ET_openbadlist-ip_reputation.feed +35 -0
- data/feeds/bambenek_c2_masterlist-domain_reputation.feed +15 -0
- data/feeds/bambenek_c2_masterlist-ip_reputation.feed +15 -0
- data/feeds/bambenek_dga_feed-domain_reputation.feed +15 -0
- data/feeds/berkeley-ip_reputation.feed +23 -0
- data/feeds/bitcash_cz_blacklist.feed +20 -0
- data/feeds/botscout-ip_reputation.feed +24 -0
- data/feeds/cert_mxpoison-ip_reputation.feed +21 -0
- data/feeds/chaosreigns-ip_reputation.feed +36 -0
- data/feeds/cydef_torexit-ip_reputation.feed +24 -0
- data/feeds/danger_bruteforce-ip_reputation.feed +23 -0
- data/feeds/falconcrest-ip_reputation.feed +18 -0
- data/feeds/h3x_asprox.feed +17 -0
- data/feeds/hosts-file_hphostspartial-domain_reputation.feed +18 -0
- data/feeds/infiltrated_vabl-ip_reputation.feed +29 -0
- data/feeds/isc_suspicious_high-domain_reputation.feed +25 -0
- data/feeds/isc_suspicious_low-domain_reputation.feed +25 -0
- data/feeds/isc_suspicious_medium-domain_reputation.feed +25 -0
- data/feeds/malwaredomainlist-url_reputation.feed +16 -0
- data/feeds/malwaredomains-domain_reputation.feed +27 -0
- data/feeds/malwaredomains_dyndns-domain_reputation.feed +27 -0
- data/feeds/malwaredomains_justdomains-domain_reputation.feed +18 -0
- data/feeds/multiproxy-ip_reputation.feed +20 -0
- data/feeds/openphish-url_reputation.feed +22 -0
- data/feeds/packetmail_perimeterbad-ip_reputation.feed +26 -0
- data/feeds/phishtank.feed +1 -1
- data/feeds/sigmaproject_atma.feed +25 -0
- data/feeds/sigmaproject_spyware.feed +24 -0
- data/feeds/sigmaproject_webexploit.feed +26 -0
- data/feeds/snort_bpf-ip_reputation.feed +19 -0
- data/feeds/steeman-ip_reputation.feed +19 -0
- data/feeds/trustedsec-ip_reputation.feed +17 -0
- data/feeds/virbl-ip_reputation.feed +24 -0
- data/feeds/vxvault-url_reputation.feed +22 -0
- data/feeds/yoyo_adservers-domain_reputation.feed +16 -0
- data/lib/threatinator/actions/run/action.rb +15 -3
- data/lib/threatinator/actions/run/coverage_observer.rb +12 -7
- data/lib/threatinator/actions/run/status_observer.rb +37 -0
- data/lib/threatinator/cli.rb +9 -3
- data/lib/threatinator/cli/parser.rb +14 -4
- data/lib/threatinator/config.rb +1 -0
- data/lib/threatinator/config/logger.rb +14 -0
- data/lib/threatinator/event.rb +28 -18
- data/lib/threatinator/event_builder.rb +52 -23
- data/lib/threatinator/exceptions.rb +3 -6
- data/lib/threatinator/feed.rb +1 -1
- data/lib/threatinator/feed_runner.rb +63 -7
- data/lib/threatinator/logger.rb +66 -0
- data/lib/threatinator/logging.rb +20 -0
- data/lib/threatinator/model/base.rb +23 -0
- data/lib/threatinator/model/collection.rb +64 -0
- data/lib/threatinator/model/observables/fqdn_collection.rb +13 -0
- data/lib/threatinator/model/observables/ipv4.rb +30 -0
- data/lib/threatinator/model/observables/ipv4_collection.rb +14 -0
- data/lib/threatinator/model/observables/url_collection.rb +16 -0
- data/lib/threatinator/model/validations.rb +1 -0
- data/lib/threatinator/model/validations/type.rb +21 -0
- data/lib/threatinator/plugins/output/csv.rb +20 -9
- data/spec/feeds/ET_block-ip_reputation_spec.rb +50 -0
- data/spec/feeds/ET_compromised-ip_reputation_spec.rb +2 -5
- data/spec/feeds/ET_openbadlist-ip_reputation_spec.rb +56 -0
- data/spec/feeds/alienvault-ip_reputation_spec.rb +2 -5
- data/spec/feeds/arbor_fastflux-domain_reputation_spec.rb +0 -3
- data/spec/feeds/arbor_ssh-ip_reputation_spec.rb +2 -5
- data/spec/feeds/autoshun_shunlist_spec.rb +1 -4
- data/spec/feeds/bambenek_c2_masterlist-domain_reputation_spec.rb +39 -0
- data/spec/feeds/bambenek_c2_masterlist-ip_reputation_spec.rb +39 -0
- data/spec/feeds/bambenek_dga_feed-domain_reputation_spec.rb +39 -0
- data/spec/feeds/berkeley-ip_reputation_spec.rb +47 -0
- data/spec/feeds/bitcash_cz_blacklist-ip_reputation_spec.rb +50 -0
- data/spec/feeds/blocklist_de_apache-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_bots-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_ftp-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_imap-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_pop3-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_proftpd-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_sip-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_ssh-ip_reputation_spec.rb +2 -5
- data/spec/feeds/blocklist_de_strongips-ip_reputation_spec.rb +2 -5
- data/spec/feeds/botscout-ip_reputation_spec.rb +50 -0
- data/spec/feeds/cert_mxpoison-ip_reputation_spec.rb +47 -0
- data/spec/feeds/chaosreigns-ip_reputation_spec.rb +50 -0
- data/spec/feeds/ciarmy-ip_reputation_spec.rb +2 -5
- data/spec/feeds/cruzit-ip_reputation_spec.rb +2 -5
- data/spec/feeds/cydef_torexit-ip_reputation_spec.rb +47 -0
- data/spec/feeds/dan_me_uk_torlist-ip_reputation_spec.rb +2 -5
- data/spec/feeds/danger_bruteforce-ip_reputation_spec.rb +47 -0
- data/spec/feeds/data/ET_block-ip_reputation.txt +80 -0
- data/spec/feeds/data/ET_openbadlist-ip_reputation.txt +62 -0
- data/spec/feeds/data/bambenek_c2-dommasterlist.csv +30 -0
- data/spec/feeds/data/bambenek_c2-ipmasterlist.csv +27 -0
- data/spec/feeds/data/bambenek_dga_feed.csv +42 -0
- data/spec/feeds/data/berkeley.txt +29 -0
- data/spec/feeds/data/bitcash_cz_blacklist.txt +7 -0
- data/spec/feeds/data/botscout-ip-reputation.txt +713 -0
- data/spec/feeds/data/cert_mxpoison-ip_reputation.txt +17 -0
- data/spec/feeds/data/chaosreigns-ip-reputation.txt +26 -0
- data/spec/feeds/data/cydef_torexit-ip_reputation.txt +27 -0
- data/spec/feeds/data/danger_bruteforce-ip_reputation.txt +12 -0
- data/spec/feeds/data/falconcrest_iplist.txt +345 -0
- data/spec/feeds/data/h3x_asprox.txt +20 -0
- data/spec/feeds/data/hosts-file_hphostspartial_domainlist.txt +24 -0
- data/spec/feeds/data/infiltrated_vabl_iplist.txt +33 -0
- data/spec/feeds/data/isc_suspicious_high_domainlist.txt +26 -0
- data/spec/feeds/data/isc_suspicious_low_domainlist.txt +34 -0
- data/spec/feeds/data/isc_suspicious_medium_domainlist.txt +32 -0
- data/spec/feeds/data/malwaredomainlist-url-reputation.txt +8 -0
- data/spec/feeds/data/malwaredomains_domainlist.txt +24 -0
- data/spec/feeds/data/malwaredomains_dyndns_domainlist.txt +34 -0
- data/spec/feeds/data/malwaredomains_justdomains_domainlist.txt +18 -0
- data/spec/feeds/data/multiproxy_iplist.txt +15 -0
- data/spec/feeds/data/openphish-url-reputation.txt +16 -0
- data/spec/feeds/data/packetmail_perimeterbad-ip_reputation.txt +44 -0
- data/spec/feeds/data/sigmaproject_atma.return.gz +0 -0
- data/spec/feeds/data/sigmaproject_spyware.return.gz +0 -0
- data/spec/feeds/data/sigmaproject_webexploit.return.gz +0 -0
- data/spec/feeds/data/snort_bpf-ip_reputation.txt +16 -0
- data/spec/feeds/data/steeman-ip-reputation.txt +13 -0
- data/spec/feeds/data/trustedsec-ip-reputation.txt +12 -0
- data/spec/feeds/data/virbl-ip_reputation.txt +14 -0
- data/spec/feeds/data/vxvault-url-reputation.txt +15 -0
- data/spec/feeds/data/yoyo_adservers.txt +25 -0
- data/spec/feeds/dshield_attackers-top1000_spec.rb +1 -4
- data/spec/feeds/falconcrest-ip_reputation_spec.rb +37 -0
- data/spec/feeds/feodo-domain_reputation_spec.rb +0 -3
- data/spec/feeds/feodo-ip_reputation_spec.rb +2 -5
- data/spec/feeds/h3x_asprox-ip_reputation_spec.rb +50 -0
- data/spec/feeds/hosts-file_hphostspartial-domain_reputation_spec.rb +47 -0
- data/spec/feeds/infiltrated-ip_reputation_spec.rb +2 -5
- data/spec/feeds/infiltrated_vabl-ip_reputation_spec.rb +47 -0
- data/spec/feeds/isc_suspicious_high-domain_reputation_spec.rb +47 -0
- data/spec/feeds/isc_suspicious_low-domain_reputation_spec.rb +47 -0
- data/spec/feeds/isc_suspicious_medium-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malc0de-domain_reputation_spec.rb +0 -3
- data/spec/feeds/malc0de-ip_reputation_spec.rb +2 -5
- data/spec/feeds/malwaredomainlist_url_reputation_spec.rb +50 -0
- data/spec/feeds/malwaredomains-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malwaredomains_dyndns-domain_reputation_spec.rb +47 -0
- data/spec/feeds/malwaredomains_justdomains-domain_reputation_spec.rb +47 -0
- data/spec/feeds/mirc-domain_reputation_spec.rb +0 -3
- data/spec/feeds/multiproxy-ip_reputation_spec.rb +47 -0
- data/spec/feeds/nothink_irc-ip_reputation_spec.rb +2 -5
- data/spec/feeds/nothink_ssh-ip_reputation_spec.rb +2 -5
- data/spec/feeds/openbl-ip_reputation_spec.rb +2 -5
- data/spec/feeds/openphish_url_reputation_spec.rb +50 -0
- data/spec/feeds/packetmail_perimeterbad-ip_reputation_spec.rb +47 -0
- data/spec/feeds/palevo-domain_reputation_spec.rb +0 -3
- data/spec/feeds/palevo-ip_reputation_spec.rb +2 -5
- data/spec/feeds/phishtank_spec.rb +2 -5
- data/spec/feeds/sigmaproject_atma_spec.rb +63 -0
- data/spec/feeds/sigmaproject_spyware_spec.rb +64 -0
- data/spec/feeds/sigmaproject_webexploit_spec.rb +63 -0
- data/spec/feeds/snort_bpf-ip_reputation_spec.rb +47 -0
- data/spec/feeds/spyeye-domain_reputation_spec.rb +0 -3
- data/spec/feeds/spyeye-ip_reputation_spec.rb +2 -5
- data/spec/feeds/steeman-ip_reputation_spec.rb +50 -0
- data/spec/feeds/t-arend-de_ssh-ip_reputation_spec.rb +2 -5
- data/spec/feeds/the_haleys_ssh-ip_reputation_spec.rb +2 -5
- data/spec/feeds/trustedsec-ip_reputation_spec.rb +47 -0
- data/spec/feeds/virbl-ip_reputation_spec.rb +47 -0
- data/spec/feeds/vxvault_url_reputation_spec.rb +50 -0
- data/spec/feeds/yourcmc_ssh-ip_reputation_spec.rb +2 -5
- data/spec/feeds/yoyo_adservers_spec.rb +47 -0
- data/spec/feeds/zeus-domain_reputation_spec.rb +0 -3
- data/spec/feeds/zeus-ip_reputation_spec.rb +2 -5
- data/spec/spec_helper.rb +2 -0
- data/spec/support/factories/event.rb +11 -7
- data/spec/support/factories/feed.rb +28 -1
- data/spec/support/factories/ipv4.rb +36 -0
- data/spec/support/factories/url.rb +34 -0
- data/spec/support/shared/feed_runner_observer.rb +136 -0
- data/spec/support/shared/feeds.rb +19 -4
- data/spec/support/shared/model/collection.rb +164 -0
- data/spec/threatinator/actions/run/action_spec.rb +27 -10
- data/spec/threatinator/actions/run/coverage_observer_spec.rb +39 -4
- data/spec/threatinator/actions/run/status_observer_spec.rb +86 -0
- data/spec/threatinator/event_builder_spec.rb +111 -21
- data/spec/threatinator/event_spec.rb +237 -13
- data/spec/threatinator/event_spec.rb.new +319 -0
- data/spec/threatinator/feed_builder_spec.rb +0 -3
- data/spec/threatinator/feed_runner_spec.rb +254 -70
- data/spec/threatinator/logger_spec.rb +29 -0
- data/spec/threatinator/model/observables/fqdn_collection_spec.rb +42 -0
- data/spec/threatinator/model/observables/ipv4_collection_spec.rb +36 -0
- data/spec/threatinator/model/observables/ipv4_spec.rb +75 -0
- data/spec/threatinator/model/observables/url_collection_spec.rb +45 -0
- data/spec/threatinator/model/validations/type_spec.rb +37 -0
- data/spec/threatinator/plugins/output/csv_spec.rb +4 -3
- metadata +216 -19
- data/lib/threatinator/property_definer.rb +0 -101
- data/spec/threatinator/property_definer_spec.rb +0 -155
|
@@ -16,12 +16,21 @@ end
|
|
|
16
16
|
|
|
17
17
|
shared_context 'a parsed feed' do
|
|
18
18
|
# expects :observer
|
|
19
|
-
let(:events) { observer.
|
|
20
|
-
let(:records) { observer.
|
|
19
|
+
let(:events) { observer.events }
|
|
20
|
+
let(:records) { observer.records }
|
|
21
21
|
let(:num_records) { observer.count }
|
|
22
22
|
let(:num_records_filtered) { observer.num_records_filtered }
|
|
23
23
|
let(:num_records_parsed) { observer.num_records_parsed }
|
|
24
24
|
let(:num_records_missed) { observer.num_records_missed }
|
|
25
|
+
let(:num_records_errored) { observer.num_records_errored }
|
|
26
|
+
|
|
27
|
+
it "should have 0 error records" do
|
|
28
|
+
expect(num_records_errored).to eq(0)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should have missed 0 records" do
|
|
32
|
+
expect(num_records_missed).to eq(0)
|
|
33
|
+
end
|
|
25
34
|
end
|
|
26
35
|
|
|
27
36
|
shared_context 'for feeds', :feed => lambda { true } do
|
|
@@ -114,7 +123,7 @@ module FeedHelpers
|
|
|
114
123
|
class FeedRunnerObserver
|
|
115
124
|
include Enumerable
|
|
116
125
|
attr_reader :records, :statuses, :events, :num_records_filtered,
|
|
117
|
-
:num_records_missed, :num_records_parsed
|
|
126
|
+
:num_records_missed, :num_records_parsed, :num_records_errored
|
|
118
127
|
|
|
119
128
|
def initialize
|
|
120
129
|
@records = []
|
|
@@ -123,6 +132,7 @@ module FeedHelpers
|
|
|
123
132
|
@num_records_filtered = 0
|
|
124
133
|
@num_records_parsed = 0
|
|
125
134
|
@num_records_missed = 0
|
|
135
|
+
@num_records_errored = 0
|
|
126
136
|
end
|
|
127
137
|
|
|
128
138
|
def each
|
|
@@ -149,6 +159,11 @@ module FeedHelpers
|
|
|
149
159
|
@statuses << :parsed
|
|
150
160
|
@events << args.shift
|
|
151
161
|
@num_records_parsed += 1
|
|
162
|
+
when :record_error
|
|
163
|
+
@records << args.shift
|
|
164
|
+
@statuses << :error
|
|
165
|
+
@events << []
|
|
166
|
+
@num_records_errored += 1
|
|
152
167
|
end
|
|
153
168
|
end
|
|
154
169
|
end
|
|
@@ -174,7 +189,7 @@ module FeedHelpers
|
|
|
174
189
|
before :each do
|
|
175
190
|
sio = StringIO.new(data)
|
|
176
191
|
feed_runner.add_observer(observer)
|
|
177
|
-
feed_runner.run(:io => sio)
|
|
192
|
+
feed_runner.run(:io => sio, :skip_decoding => true)
|
|
178
193
|
@status, @record, @events = observer.first
|
|
179
194
|
end
|
|
180
195
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples_for "a model collection" do
|
|
4
|
+
# expect generate_ten_valid_members, generate_invalid_members
|
|
5
|
+
let(:collection) { described_class.new }
|
|
6
|
+
|
|
7
|
+
describe "initialize" do
|
|
8
|
+
context "when no parameters are provided" do
|
|
9
|
+
specify "the collection is empty" do
|
|
10
|
+
x = described_class.new
|
|
11
|
+
expect(x).to be_empty
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context "when an array of members is provided" do
|
|
16
|
+
it "calls #<< for each member, adding it to the collection" do
|
|
17
|
+
members = generate_ten_valid_members()
|
|
18
|
+
expect_any_instance_of(described_class).to receive(:<<).exactly(10).times.and_call_original
|
|
19
|
+
x = described_class.new(members)
|
|
20
|
+
expect(x.to_a).to match_array(members)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
describe "#<<(member)" do
|
|
25
|
+
it "adds the member to the collection" do
|
|
26
|
+
member = generate_ten_valid_members()[0]
|
|
27
|
+
expect(collection.include?(member)).to eq(false)
|
|
28
|
+
collection << member
|
|
29
|
+
expect(collection.include?(member)).to eq(true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "does not add the member if it is equal to any member of the collection" do
|
|
33
|
+
member = generate_ten_valid_members()[0]
|
|
34
|
+
expect(collection.count).to eq(0)
|
|
35
|
+
collection << member
|
|
36
|
+
expect(collection.count).to eq(1)
|
|
37
|
+
collection << member
|
|
38
|
+
expect(collection.count).to eq(1)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "raises InvalidAttributeError if the added member is not valid for the collection" do
|
|
42
|
+
expect {
|
|
43
|
+
collection << generate_invalid_members()[0]
|
|
44
|
+
}.to raise_error(Threatinator::Exceptions::InvalidAttributeError)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "#valid_member?(member)" do
|
|
49
|
+
it "returns true if the member is valid" do
|
|
50
|
+
expect(collection.valid_member?(generate_ten_valid_members()[0])).to eq(true)
|
|
51
|
+
end
|
|
52
|
+
it "returns false if the member is not valid" do
|
|
53
|
+
expect(collection.valid_member?(generate_invalid_members()[0])).to eq(false)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "#include?(member)" do
|
|
58
|
+
let(:member) { generate_ten_valid_members()[0] }
|
|
59
|
+
it "returns true if the member is in the collection" do
|
|
60
|
+
collection << member
|
|
61
|
+
expect(collection).to include(member)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "returns false if the member is not in the collection" do
|
|
65
|
+
expect(collection).not_to include(member)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "#empty?" do
|
|
70
|
+
it "returns true when the collection is empty" do
|
|
71
|
+
expect(collection).to be_empty
|
|
72
|
+
end
|
|
73
|
+
it "returns false when something has been added to the collection" do
|
|
74
|
+
member = generate_ten_valid_members()[0]
|
|
75
|
+
collection << member
|
|
76
|
+
expect(collection).not_to be_empty
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe "#count" do
|
|
81
|
+
it "returns 0 when the collection is empty" do
|
|
82
|
+
expect(collection.count).to eq(0)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "returns the number of members in the collection" do
|
|
86
|
+
members = generate_ten_valid_members()
|
|
87
|
+
members.each do |member|
|
|
88
|
+
collection << member
|
|
89
|
+
end
|
|
90
|
+
expect(collection.count).to eq(members.count)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
[:to_ary, :to_a].each do |method_name|
|
|
95
|
+
describe "##{method_name}" do
|
|
96
|
+
it "returns an empty array instance when the collection is empty" do
|
|
97
|
+
expect(collection.send(method_name)).to eq([])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "returns an array containing members that have been added" do
|
|
101
|
+
members = generate_ten_valid_members()
|
|
102
|
+
members.each do |member|
|
|
103
|
+
collection << member
|
|
104
|
+
end
|
|
105
|
+
expect(collection.send(method_name)).to match_array(members)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe "#each" do
|
|
111
|
+
it "returns an Enumerator if no block is provided" do
|
|
112
|
+
expect(collection.each).to be_a(::Enumerator)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "yields each member of the collection" do
|
|
116
|
+
members = generate_ten_valid_members()
|
|
117
|
+
members.each do |member|
|
|
118
|
+
collection << member
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
actual = []
|
|
122
|
+
collection.each do |member|
|
|
123
|
+
actual << member
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
expect(actual).to match_array(members)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
describe "#==(other)" do
|
|
131
|
+
before :each do
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "returns true when compared to itself" do
|
|
135
|
+
collection = described_class.new(generate_ten_valid_members())
|
|
136
|
+
expect(collection).to be == collection
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "returns true when compared to a collection with equal members" do
|
|
140
|
+
collection = described_class.new(generate_ten_valid_members())
|
|
141
|
+
collection2 = described_class.new(generate_ten_valid_members())
|
|
142
|
+
expect(collection).to be == collection2
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "returns false if the number of members is different" do
|
|
146
|
+
collection = described_class.new(generate_ten_valid_members()[0..5])
|
|
147
|
+
collection2 = described_class.new(generate_ten_valid_members())
|
|
148
|
+
expect(collection).not_to be == collection2
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "returns false if the members are different" do
|
|
152
|
+
collection = described_class.new(generate_ten_valid_members()[0..4])
|
|
153
|
+
collection2 = described_class.new(generate_ten_valid_members()[5..9])
|
|
154
|
+
expect(collection).not_to be == collection2
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "returns false when compared to something other than a collection" do
|
|
158
|
+
members = generate_ten_valid_members()
|
|
159
|
+
collection = described_class.new(members)
|
|
160
|
+
expect(collection).not_to be == members
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
@@ -31,35 +31,52 @@ describe Threatinator::Actions::Run::Action do
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
describe "#exec" do
|
|
34
|
-
before :each do
|
|
35
|
-
@ret = action.exec
|
|
36
|
-
end
|
|
37
34
|
|
|
38
35
|
it "queries the feed registry for the provider and name" do
|
|
36
|
+
action.exec
|
|
39
37
|
expect(feed_registry).to have_received(:get).with("my_provider", "my_name")
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
it "builds the output using config.output.build_output" do
|
|
41
|
+
action.exec
|
|
43
42
|
expect(config.output).to have_received(:build_output)
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
it "runs the feed" do
|
|
46
|
+
action.exec
|
|
47
47
|
expect(feed_runner).to have_received(:run)
|
|
48
48
|
end
|
|
49
|
-
end
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
context "when a record was missed" do
|
|
51
|
+
let(:status_observer) { Threatinator::Actions::Run::StatusObserver.new }
|
|
52
|
+
before :each do
|
|
53
|
+
allow(Threatinator::Actions::Run::StatusObserver).to receive(:new).and_return(status_observer)
|
|
54
|
+
allow(status_observer).to receive(:missed?).and_return(true)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "logs an error message" do
|
|
58
|
+
expect(action.logger).to receive(:error).with(/records were MISSED/)
|
|
59
|
+
action.exec
|
|
60
|
+
end
|
|
54
61
|
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
|
|
63
|
+
context "when a record had an error" do
|
|
64
|
+
let(:status_observer) { Threatinator::Actions::Run::StatusObserver.new }
|
|
65
|
+
before :each do
|
|
66
|
+
allow(Threatinator::Actions::Run::StatusObserver).to receive(:new).and_return(status_observer)
|
|
67
|
+
allow(status_observer).to receive(:errors?).and_return(true)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "logs an error message" do
|
|
71
|
+
expect(action.logger).to receive(:error).with(/records had errors/)
|
|
72
|
+
action.exec
|
|
73
|
+
end
|
|
58
74
|
end
|
|
59
75
|
end
|
|
60
76
|
|
|
61
77
|
context "when configured with an observer" do
|
|
62
78
|
before :each do
|
|
79
|
+
allow(feed_runner).to receive(:add_observer)
|
|
63
80
|
config.observers = [ observer ]
|
|
64
81
|
end
|
|
65
82
|
|
|
@@ -14,6 +14,8 @@ describe Threatinator::Actions::Run::CoverageObserver do
|
|
|
14
14
|
let(:filename) { File.join(@tmpdir, "coverage.csv") }
|
|
15
15
|
let(:observer) { described_class.new(filename) }
|
|
16
16
|
|
|
17
|
+
it_should_behave_like "a FeedRunner observer"
|
|
18
|
+
|
|
17
19
|
context "#update(:start)" do
|
|
18
20
|
it "creates the file specified by filename" do
|
|
19
21
|
expect(File.exist?(filename)).to eq(false)
|
|
@@ -35,7 +37,7 @@ describe Threatinator::Actions::Run::CoverageObserver do
|
|
|
35
37
|
|
|
36
38
|
specify "the first line is the header" do
|
|
37
39
|
data = File.read(filename)
|
|
38
|
-
expect(data.lines.to_a.first).to eq("status,event_count,line_number,pos_start,pos_end,data\n")
|
|
40
|
+
expect(data.lines.to_a.first).to eq("status,event_count,line_number,pos_start,pos_end,data,message\n")
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
it "closes the file so that no more records will be written" do
|
|
@@ -65,7 +67,8 @@ describe Threatinator::Actions::Run::CoverageObserver do
|
|
|
65
67
|
line_number: "23",
|
|
66
68
|
pos_start: "99",
|
|
67
69
|
pos_end: "105",
|
|
68
|
-
data: '"foobar\r\n"'
|
|
70
|
+
data: '"foobar\r\n"',
|
|
71
|
+
message: ''
|
|
69
72
|
)
|
|
70
73
|
end
|
|
71
74
|
end
|
|
@@ -86,7 +89,8 @@ describe Threatinator::Actions::Run::CoverageObserver do
|
|
|
86
89
|
line_number: "22",
|
|
87
90
|
pos_start: "98",
|
|
88
91
|
pos_end: "104",
|
|
89
|
-
data: '"blabla\r\n"'
|
|
92
|
+
data: '"blabla\r\n"',
|
|
93
|
+
message: ''
|
|
90
94
|
)
|
|
91
95
|
end
|
|
92
96
|
end
|
|
@@ -109,7 +113,38 @@ describe Threatinator::Actions::Run::CoverageObserver do
|
|
|
109
113
|
line_number: "1",
|
|
110
114
|
pos_start: "0",
|
|
111
115
|
pos_end: "10",
|
|
112
|
-
data: '"woofwoof\r\n"'
|
|
116
|
+
data: '"woofwoof\r\n"',
|
|
117
|
+
message: ''
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
context "#update(:record_error, record, errors)" do
|
|
123
|
+
before :each do
|
|
124
|
+
observer.update(:start)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
let(:record) { build(:record, line_number: 1, pos_start: 0, pos_end: 10, data: "woofwoof\r\n") }
|
|
128
|
+
let(:errors) {
|
|
129
|
+
[
|
|
130
|
+
Threatinator::Exceptions::EventBuildError.new("error 1"),
|
|
131
|
+
Threatinator::Exceptions::EventBuildError.new("error 2"),
|
|
132
|
+
Threatinator::Exceptions::EventBuildError.new("error 3")
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
it "writes a csv entry to the file indicating it encountered an error, with the error messages" do
|
|
137
|
+
observer.update(:record_error, record, errors)
|
|
138
|
+
observer.update(:end)
|
|
139
|
+
csv = CSV.read(filename, headers: true, header_converters: :symbol)
|
|
140
|
+
expect(csv[-1].to_hash).to eq(
|
|
141
|
+
status: "error",
|
|
142
|
+
event_count: "0",
|
|
143
|
+
line_number: "1",
|
|
144
|
+
pos_start: "0",
|
|
145
|
+
pos_end: "10",
|
|
146
|
+
data: '"woofwoof\r\n"',
|
|
147
|
+
message: 'error 1, error 2, error 3'
|
|
113
148
|
)
|
|
114
149
|
end
|
|
115
150
|
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'threatinator/actions/run/status_observer'
|
|
3
|
+
|
|
4
|
+
describe Threatinator::Actions::Run::StatusObserver do
|
|
5
|
+
let(:observer) { described_class.new() }
|
|
6
|
+
let(:record) { build(:record, line_number: 23, pos_start: 99, pos_end: 105, data: "foobar\r\n") }
|
|
7
|
+
|
|
8
|
+
it_should_behave_like "a FeedRunner observer"
|
|
9
|
+
|
|
10
|
+
describe "#filtered" do
|
|
11
|
+
it "returns the number of records that have been filtered" do
|
|
12
|
+
expect(observer.filtered).to eq(0)
|
|
13
|
+
observer.update(:record_filtered, record)
|
|
14
|
+
expect(observer.filtered).to eq(1)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#filtered?" do
|
|
19
|
+
it "returns true if any records were filtered, false otherwise" do
|
|
20
|
+
expect(observer.filtered?).to eq(false)
|
|
21
|
+
observer.update(:record_filtered, record)
|
|
22
|
+
expect(observer.filtered?).to eq(true)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#missed" do
|
|
27
|
+
it "returns the number of records that have been missed" do
|
|
28
|
+
expect(observer.missed).to eq(0)
|
|
29
|
+
observer.update(:record_missed, record)
|
|
30
|
+
expect(observer.missed).to eq(1)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#missed?" do
|
|
35
|
+
it "returns true if any records were missed, false otherwise" do
|
|
36
|
+
expect(observer.missed?).to eq(false)
|
|
37
|
+
observer.update(:record_missed, record)
|
|
38
|
+
expect(observer.missed?).to eq(true)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "#parsed" do
|
|
43
|
+
it "returns the number of records that have been parsed" do
|
|
44
|
+
expect(observer.parsed).to eq(0)
|
|
45
|
+
observer.update(:record_parsed, record)
|
|
46
|
+
expect(observer.parsed).to eq(1)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "#parsed?" do
|
|
51
|
+
it "returns true if any records were parsed, false otherwise" do
|
|
52
|
+
expect(observer.parsed?).to eq(false)
|
|
53
|
+
observer.update(:record_parsed, record)
|
|
54
|
+
expect(observer.parsed?).to eq(true)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "#errors" do
|
|
59
|
+
it "returns the number of records that had errors" do
|
|
60
|
+
expect(observer.errors).to eq(0)
|
|
61
|
+
observer.update(:record_error, record)
|
|
62
|
+
expect(observer.errors).to eq(1)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "#errors?" do
|
|
67
|
+
it "returns true if any records had errors, false otherwise" do
|
|
68
|
+
expect(observer.errors?).to eq(false)
|
|
69
|
+
observer.update(:record_error, record)
|
|
70
|
+
expect(observer.errors?).to eq(true)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
describe "#total" do
|
|
76
|
+
it "returns the total number of records that were parsed, missed, filtered, and errored" do
|
|
77
|
+
expect(observer.total).to eq(0)
|
|
78
|
+
10.times { observer.update(:record_parsed, record) }
|
|
79
|
+
10.times { observer.update(:record_missed, record) }
|
|
80
|
+
10.times { observer.update(:record_filtered, record) }
|
|
81
|
+
10.times { observer.update(:record_error, record) }
|
|
82
|
+
expect(observer.total).to eq(40)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|