cve_crawler 0.2.0 → 0.3.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/lib/cve_crawler/cve_core.rb +3 -1
- data/lib/cve_crawler/cve_filter.rb +3 -3
- data/lib/cve_crawler/cve_parser.rb +2 -1
- data/lib/cve_crawler/cve_vulnerability.rb +11 -0
- data/spec/core_spec.rb +61 -0
- data/spec/filter_spec.rb +65 -0
- data/spec/parser_spec.rb +15 -0
- data/spec/spec_helper.rb +13 -76
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31c7faeb4c2a75bb522bd206fc7cde12de39fee6
|
4
|
+
data.tar.gz: b0f13771e93ec38491348ef6eb0b35f537c0a843
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3022536ed2bf42f437d8942a883abaa9e3125fe6ce4ab85056f776488da02080f3a370d742180a5faa88f4084e3e44023d93789bd32f00decd2834742f554085
|
7
|
+
data.tar.gz: c701cf723c1eed68b70261c92f08400a5a84495445bb9936dee050a3a821f1349e744b2c28c36beebb6ee1c0bf809c90d80f02ddf503a0bd3fd0857c9006fa9d
|
data/lib/cve_crawler/cve_core.rb
CHANGED
@@ -4,7 +4,7 @@ require 'cve_crawler/cve_parser'
|
|
4
4
|
|
5
5
|
module CVE
|
6
6
|
VERSION_MAJOR = 0
|
7
|
-
VERSION_MINOR =
|
7
|
+
VERSION_MINOR = 3
|
8
8
|
VERSION_BUILD = 0
|
9
9
|
VERSION = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_BUILD}".freeze
|
10
10
|
|
@@ -18,6 +18,8 @@ module CVE
|
|
18
18
|
@parser = Parser.new(filters)
|
19
19
|
end
|
20
20
|
|
21
|
+
attr_reader :crawler, :parser
|
22
|
+
|
21
23
|
def fetch
|
22
24
|
body = crawl.body
|
23
25
|
parse(body)
|
@@ -5,7 +5,7 @@ module CVE
|
|
5
5
|
@history_size = history_size
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
attr_accessor :history, :history_size
|
9
9
|
|
10
10
|
def filter(contents)
|
11
11
|
return true unless contents.is_a?(Vulnerability)
|
@@ -23,8 +23,8 @@ module CVE
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def history_check_limit
|
26
|
-
if @history.length
|
27
|
-
@history.drop(
|
26
|
+
if @history.length > @history_size
|
27
|
+
@history = @history.drop(@history.length - @history_size)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -6,7 +6,6 @@ module CVE
|
|
6
6
|
class Parser
|
7
7
|
def initialize(filters=nil)
|
8
8
|
@filters = []
|
9
|
-
|
10
9
|
@filters << CVE::Filter.new
|
11
10
|
|
12
11
|
if filters.is_a?(Array)
|
@@ -18,6 +17,8 @@ module CVE
|
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
20
|
+
attr_reader :filters
|
21
|
+
|
21
22
|
def parse(content)
|
22
23
|
results = parse_rss_feed(content)
|
23
24
|
|
@@ -55,6 +55,17 @@ module CVE
|
|
55
55
|
"#{@title} - #{@link}"
|
56
56
|
end
|
57
57
|
|
58
|
+
def to_hash
|
59
|
+
{
|
60
|
+
:identifier => @identifier,
|
61
|
+
:title => @title,
|
62
|
+
:link => @link,
|
63
|
+
:description => @description,
|
64
|
+
:date => @date,
|
65
|
+
:affected_software => @affected_software
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
58
69
|
def inspect
|
59
70
|
"#<CVE::Vulnerability id=#{@identifier} affected=#{affected_count}>"
|
60
71
|
end
|
data/spec/core_spec.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
# Not exactly what it says on the tin: Everything here is faked to simulate an environment
|
4
|
+
# where you can dynamically crawl, parse, filter and generate new vulnerabilities like the
|
5
|
+
# real RSS feed would. This simply simulates that behaviour to verify the system as a whole
|
6
|
+
# still functions. These tests failing might not necessarily represent a failure in the core
|
7
|
+
# but are more likely to represent a failure in one of the components.
|
8
|
+
describe CVE::Core do
|
9
|
+
core = CoreMock.new
|
10
|
+
|
11
|
+
it 'should fetch new results without error' do
|
12
|
+
expect{ core.fetch }.not_to raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should list new vulnerabilities when CVE::Core#fetch is called and new vulnerabilities exist' do
|
16
|
+
result = core.fetch
|
17
|
+
|
18
|
+
expect(result.count).not_to eq(0)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return a list of CVE::Vulnerability when vulnerabilities have been found' do
|
22
|
+
result = core.fetch
|
23
|
+
|
24
|
+
result.each do |res|
|
25
|
+
expect(res).to be_a(CVE::Vulnerability)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not list old vulnerabilities when CVE::Core#fetch is called' do
|
30
|
+
tmp_core = create_core_object
|
31
|
+
|
32
|
+
old_cves = tmp_core.fetch
|
33
|
+
new_cves = tmp_core.fetch
|
34
|
+
|
35
|
+
new_cves.each do |new|
|
36
|
+
old_cves.each do |old|
|
37
|
+
expect(new.identifier).not_to eq(old.identifier)
|
38
|
+
expect(new.equal?(old)).to eq(false)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should append as many items to the history as were fetched' do
|
44
|
+
tmp_core = create_core_object
|
45
|
+
|
46
|
+
result = tmp_core.fetch
|
47
|
+
|
48
|
+
expect(tmp_core.parser.filters[0].history.count).to eq(result.count)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should append new items to the history of the filter' do
|
52
|
+
tmp_core = create_core_object
|
53
|
+
|
54
|
+
tmp_core.fetch
|
55
|
+
current_history_size = tmp_core.parser.filters[0].history.count
|
56
|
+
result = tmp_core.fetch
|
57
|
+
|
58
|
+
expect(tmp_core.parser.filters[0].history.count).not_to eq(current_history_size)
|
59
|
+
expect(tmp_core.parser.filters[0].history.count).to eq(current_history_size + result.count)
|
60
|
+
end
|
61
|
+
end
|
data/spec/filter_spec.rb
CHANGED
@@ -16,4 +16,69 @@ describe CVE::Filter do
|
|
16
16
|
expect(filter.filter(VulnerabilityMock.generate)).to equal(false)
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
it 'should not exceed the history limit imposed' do
|
21
|
+
filter = CVE::Filter.new
|
22
|
+
|
23
|
+
filter_fill_history(filter, filter.history_size + 1)
|
24
|
+
|
25
|
+
expect(filter.history.count).to eq(filter.history_size)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not exceed the history limit customly set' do
|
29
|
+
filter = CVE::Filter.new(3)
|
30
|
+
expect(filter.history_size).to eq(3)
|
31
|
+
|
32
|
+
filter_fill_history(filter, filter.history_size + 1)
|
33
|
+
|
34
|
+
expect(filter.history.count).to eq(filter.history_size)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not store duplicate history entries' do
|
38
|
+
filter = CVE::Filter.new
|
39
|
+
cve = VulnerabilityMock.generate
|
40
|
+
|
41
|
+
filter.filter(cve)
|
42
|
+
filter.filter(cve)
|
43
|
+
|
44
|
+
expect(filter.history.count).to eq(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should remove older history items first' do
|
48
|
+
filter = CVE::Filter.new(1)
|
49
|
+
cve = VulnerabilityMock.generate
|
50
|
+
|
51
|
+
filter.filter(cve)
|
52
|
+
filter.filter(VulnerabilityMock.generate)
|
53
|
+
|
54
|
+
expect(filter.history[0]).not_to eq(cve)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should remove older history items first' do
|
58
|
+
filter = CVE::Filter.new(5)
|
59
|
+
batches = []
|
60
|
+
batch = []
|
61
|
+
|
62
|
+
2.times do
|
63
|
+
5.times do
|
64
|
+
batch << VulnerabilityMock.generate
|
65
|
+
end
|
66
|
+
batches << batch
|
67
|
+
batch = []
|
68
|
+
end
|
69
|
+
|
70
|
+
expect {
|
71
|
+
batches.each do |vulns|
|
72
|
+
vulns.each do |vuln|
|
73
|
+
raise 'Unique filtered content was determined to be filtered?' if filter.filter(vuln) == true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}.not_to raise_error
|
77
|
+
|
78
|
+
history_ok = true
|
79
|
+
5.times do |i|
|
80
|
+
history_ok = history_ok && filter.history[i] == batches[1][i].identifier
|
81
|
+
end
|
82
|
+
expect(history_ok).to equal(true)
|
83
|
+
end
|
19
84
|
end
|
data/spec/parser_spec.rb
CHANGED
@@ -22,6 +22,21 @@ describe CVE::Parser do
|
|
22
22
|
expect{ parser.parse('Not xml') }.to raise_error(RuntimeError)
|
23
23
|
end
|
24
24
|
|
25
|
+
it 'should parse individual items' do
|
26
|
+
vulns = []
|
27
|
+
|
28
|
+
3.times do
|
29
|
+
vulns << VulnerabilityMock.generate
|
30
|
+
end
|
31
|
+
|
32
|
+
contents = RSSMock.new(vulns)
|
33
|
+
items = parser.parse_items(contents)
|
34
|
+
|
35
|
+
3.times do |i|
|
36
|
+
expect(items[i].equal?(vulns[i])).to eq(true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
25
40
|
it 'should extract the CVE identifier from a title' do
|
26
41
|
title = VulnerabilityMock.new.title
|
27
42
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,84 +1,21 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require_relative File.join('..', 'lib', 'cve_crawler')
|
3
|
+
require_relative 'mocks/rss_mock'
|
4
|
+
require_relative 'mocks/cve_crawler_mock'
|
5
|
+
require_relative 'mocks/vulnerability_mock'
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
8
|
-
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
9
|
-
<channel rdf:about="http://web.nvd.nist.gov/view/vuln/search">
|
10
|
-
<title>National Vulnerability Database</title>
|
11
|
-
<link>http://web.nvd.nist.gov/view/vuln/search</link>
|
12
|
-
<description>This feed contains the most recent CVE cyber vulnerabilities published within the National Vulnerability Database.</description>
|
13
|
-
<items>
|
14
|
-
<rdf:Seq>
|
15
|
-
<rdf:li rdf:resource="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4476" />
|
16
|
-
<rdf:li rdf:resource="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4500" />
|
17
|
-
<rdf:li rdf:resource="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4501" />
|
18
|
-
</rdf:Seq>
|
19
|
-
</items>
|
20
|
-
<dc:date>2015-09-27T04:50:00Z</dc:date>
|
21
|
-
<dc:language>en-us</dc:language>
|
22
|
-
<dc:rights>This material is not copywritten and may be freely used, however, attribution is requested.</dc:rights>
|
23
|
-
</channel>
|
24
|
-
<item rdf:about="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4476">
|
25
|
-
<title>CVE-2015-4476 (firefox)</title>
|
26
|
-
<link>http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4476</link>
|
27
|
-
<description>Mozilla Firefox before 41.0 on Android allows user-assisted remote attackers to spoof address-bar attributes by leveraging lack of navigation after a paste of a URL with a nonstandard scheme, as demonstrated by spoofing an SSL attribute.</description>
|
28
|
-
<dc:date>2015-09-24T04:59:00Z</dc:date>
|
29
|
-
</item>
|
30
|
-
<item rdf:about="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4500">
|
31
|
-
<title>CVE-2015-4500 (firefox, firefox_esr)</title>
|
32
|
-
<link>http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4500</link>
|
33
|
-
<description>Multiple unspecified vulnerabilities in the browser engine in Mozilla Firefox before 41.0 and Firefox ESR 38.x before 38.3 allow remote attackers to cause a denial of service (memory corruption and application crash) or possibly execute arbitrary code via unknown vectors.</description>
|
34
|
-
<dc:date>2015-09-24T04:59:02Z</dc:date>
|
35
|
-
</item>
|
36
|
-
<item rdf:about="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4501">
|
37
|
-
<title>CVE-2015-4501 (firefox)</title>
|
38
|
-
<link>http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4501</link>
|
39
|
-
<description>Multiple unspecified vulnerabilities in the browser engine in Mozilla Firefox before 41.0 allow remote attackers to cause a denial of service (memory corruption and application crash) or possibly execute arbitrary code via unknown vectors.</description>
|
40
|
-
<dc:date>2015-09-24T04:59:03Z</dc:date>
|
41
|
-
</item>
|
42
|
-
</rdf:RDF>
|
43
|
-
eos
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class VulnerabilityMock
|
48
|
-
def self.generate
|
49
|
-
mocker = VulnerabilityMock.new
|
50
|
-
id = mocker.identifier
|
51
|
-
|
52
|
-
CVE::Vulnerability.new({
|
53
|
-
:identifier => id,
|
54
|
-
:title => mocker.title(id),
|
55
|
-
:link => mocker.link(id),
|
56
|
-
:description => mocker.description,
|
57
|
-
:date => mocker.date
|
58
|
-
})
|
59
|
-
end
|
60
|
-
|
61
|
-
def identifier
|
62
|
-
year = Time.now.year
|
63
|
-
"CVE-#{rand(2000..year)}-#{rand(0..9999)}"
|
7
|
+
def filter_fill_history(filter, size)
|
8
|
+
size.times do
|
9
|
+
filter.filter(VulnerabilityMock.generate)
|
64
10
|
end
|
65
11
|
|
66
|
-
|
67
|
-
|
68
|
-
'Firefox', 'Chromium', 'Thunderbird'].sample.split('').shuffle.join + ')'
|
69
|
-
end
|
70
|
-
|
71
|
-
def link(id=nil)
|
72
|
-
'http://web.nvd.nist.gov/view/vuln/detail?vulnId=' + (id || identifier)
|
73
|
-
end
|
12
|
+
filter
|
13
|
+
end
|
74
14
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
15
|
+
def create_core_object
|
16
|
+
# Ensure a clear history and a large history buffer to avoid tests failing when the limit is reached
|
17
|
+
tmp_core = CoreMock.new
|
18
|
+
tmp_core.parser.filters[0].history_size = 50 if tmp_core.parser.filters[0].history_size < 50
|
80
19
|
|
81
|
-
|
82
|
-
Time.now
|
83
|
-
end
|
20
|
+
tmp_core
|
84
21
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cve_crawler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jos Ahrens
|
@@ -22,6 +22,7 @@ files:
|
|
22
22
|
- lib/cve_crawler/cve_filter.rb
|
23
23
|
- lib/cve_crawler/cve_parser.rb
|
24
24
|
- lib/cve_crawler/cve_vulnerability.rb
|
25
|
+
- spec/core_spec.rb
|
25
26
|
- spec/crawler_spec.rb
|
26
27
|
- spec/filter_spec.rb
|
27
28
|
- spec/parser_spec.rb
|