cvelist 0.1.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 +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +29 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +10 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.md +82 -0
- data/Rakefile +13 -0
- data/benchmark.rb +38 -0
- data/cvelist.gemspec +61 -0
- data/gemspec.yml +21 -0
- data/lib/cvelist.rb +2 -0
- data/lib/cvelist/cve.rb +83 -0
- data/lib/cvelist/directory.rb +80 -0
- data/lib/cvelist/exceptions.rb +31 -0
- data/lib/cvelist/malformed_cve.rb +42 -0
- data/lib/cvelist/range_dir.rb +121 -0
- data/lib/cvelist/repository.rb +240 -0
- data/lib/cvelist/version.rb +4 -0
- data/lib/cvelist/year_dir.rb +178 -0
- data/spec/cve_methods_examples.rb +130 -0
- data/spec/cve_spec.rb +51 -0
- data/spec/cvelist_spec.rb +8 -0
- data/spec/directory_spec.rb +83 -0
- data/spec/fixtures/CVE-2020-1994.json +140 -0
- data/spec/fixtures/cvelist/.gitkeep +0 -0
- data/spec/fixtures/cvelist/1999/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2000/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2001/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2002/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2003/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2004/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2005/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2006/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2007/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2008/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2009/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2010/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2011/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2012/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2013/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2014/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2015/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2016/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2017/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2018/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2019/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2020/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/0xxx/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/1xxx/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/20xxx/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/21xxx/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/2xxx/.gitkeep +0 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2000.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2001.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2002.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2003.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2004.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2005.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2006.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2007.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2008.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2009.json +18 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2998.json +3 -0
- data/spec/fixtures/cvelist/2021/2xxx/CVE-2021-2999.json +2 -0
- data/spec/range_dir_spec.rb +55 -0
- data/spec/repository_spec.rb +248 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/year_dir_spec.rb +96 -0
- metadata +165 -0
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2000",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2001",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2002",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2003",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2004",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2005",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2006",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2007",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2008",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"data_type": "CVE",
|
3
|
+
"data_format": "MITRE",
|
4
|
+
"data_version": "4.0",
|
5
|
+
"CVE_data_meta": {
|
6
|
+
"ID": "CVE-2021-2009",
|
7
|
+
"ASSIGNER": "cve@mitre.org",
|
8
|
+
"STATE": "RESERVED"
|
9
|
+
},
|
10
|
+
"description": {
|
11
|
+
"description_data": [
|
12
|
+
{
|
13
|
+
"lang": "eng",
|
14
|
+
"value": "** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided."
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cve_methods_examples'
|
3
|
+
require 'cvelist/range_dir'
|
4
|
+
|
5
|
+
describe RangeDir do
|
6
|
+
let(:year_number) { 2021 }
|
7
|
+
let(:xxx_range) { '2xxx' }
|
8
|
+
|
9
|
+
let(:fixture_dir) { File.expand_path('../fixtures',__FILE__) }
|
10
|
+
let(:cvelist_dir) { File.join(fixture_dir,'cvelist') }
|
11
|
+
let(:path) { File.join(cvelist_dir,year_number.to_s,xxx_range) }
|
12
|
+
|
13
|
+
subject { described_class.new(path) }
|
14
|
+
|
15
|
+
describe "#initialize" do
|
16
|
+
it "must set #range" do
|
17
|
+
expect(subject.range).to eq(xxx_range)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:valid_cve_files) do
|
22
|
+
%w[
|
23
|
+
CVE-2021-2000.json CVE-2021-2003.json CVE-2021-2006.json CVE-2021-2009.json
|
24
|
+
CVE-2021-2001.json CVE-2021-2004.json CVE-2021-2007.json
|
25
|
+
CVE-2021-2002.json CVE-2021-2005.json CVE-2021-2008.json
|
26
|
+
]
|
27
|
+
end
|
28
|
+
let(:malformed_cve_files) { %w[CVE-2021-2998.json CVE-2021-2999.json] }
|
29
|
+
|
30
|
+
let(:cve_files) { valid_cve_files + malformed_cve_files }
|
31
|
+
let(:cve_paths) do
|
32
|
+
cve_files.map { |file| File.join(path,file) }
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:sorted_cve_files) { cve_files.sort }
|
36
|
+
let(:sorted_cve_paths) do
|
37
|
+
sorted_cve_files.map { |file| File.join(path,file) }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#files" do
|
41
|
+
it "must find all CVE-*.json files" do
|
42
|
+
expect(subject.files).to all(be =~ /\/CVE-\d{4}-\d{4}\.json$/)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must return the paths to 'CVE-*.json' files within the range directory" do
|
46
|
+
expect(subject.files).to match_array(cve_paths)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must sort the 'CVE-*.json' files" do
|
50
|
+
expect(subject.files).to eq(sorted_cve_paths)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
include_examples "CVE methods"
|
55
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cve_methods_examples'
|
3
|
+
require 'cvelist/repository'
|
4
|
+
|
5
|
+
describe Repository do
|
6
|
+
let(:fixture_dir) { File.expand_path('../fixtures',__FILE__) }
|
7
|
+
let(:cvelist_dir) { File.join(fixture_dir,'cvelist') }
|
8
|
+
|
9
|
+
describe ".clone" do
|
10
|
+
subject { described_class }
|
11
|
+
|
12
|
+
let(:depth) { 1 }
|
13
|
+
let(:url) { described_class::URL }
|
14
|
+
let(:path) { File.join(fixture_dir,'new_cvelist') }
|
15
|
+
|
16
|
+
context "when only given the path argument" do
|
17
|
+
it "must execute `git clone --depth 1 URL path` command" do
|
18
|
+
expect(subject).to receive(:system).with(
|
19
|
+
'git', 'clone', '--depth', depth.to_s, url, path
|
20
|
+
).and_return(true)
|
21
|
+
|
22
|
+
subject.clone(path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when given a custom url: argument" do
|
27
|
+
let(:url) { 'https://github.com/some_other/cvelist.git' }
|
28
|
+
|
29
|
+
it "must pass the `URL` git argument to `git clone`" do
|
30
|
+
expect(subject).to receive(:system).with(
|
31
|
+
'git', 'clone', '--depth', depth.to_s, url, path
|
32
|
+
).and_return(true)
|
33
|
+
|
34
|
+
subject.clone(path, url: url)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when given a custom depth: argument" do
|
39
|
+
let(:depth) { 2 }
|
40
|
+
|
41
|
+
it "must pass the `--depth DEPTH` option to `git clone`" do
|
42
|
+
expect(subject).to receive(:system).with(
|
43
|
+
'git', 'clone', '--depth', depth.to_s, url, path
|
44
|
+
).and_return(true)
|
45
|
+
|
46
|
+
subject.clone(path, depth: depth)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the `git clone` command succeeds" do
|
51
|
+
it do
|
52
|
+
expect(subject).to receive(:system).with(
|
53
|
+
'git', 'clone', '--depth', depth.to_s, url, path
|
54
|
+
).and_return(true)
|
55
|
+
|
56
|
+
expect(subject.clone(path)).to be_kind_of(described_class)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when the `git clone` command fails" do
|
61
|
+
it do
|
62
|
+
expect(subject).to receive(:system).with(
|
63
|
+
'git', 'clone', '--depth', depth.to_s, url, path
|
64
|
+
).and_return(false)
|
65
|
+
|
66
|
+
expect {
|
67
|
+
subject.clone(path)
|
68
|
+
}.to raise_error(GitCloneFailed)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
let(:path) { cvelist_dir }
|
74
|
+
|
75
|
+
subject { described_class.new(path) }
|
76
|
+
|
77
|
+
describe "#git?" do
|
78
|
+
it "must test for the presence of a '.git' directory" do
|
79
|
+
expect(subject).to receive(:directory?).with('.git')
|
80
|
+
|
81
|
+
subject.git?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#pull!" do
|
86
|
+
context "when the repository is a git repository" do
|
87
|
+
before { expect(subject).to receive(:git?).and_return(true) }
|
88
|
+
|
89
|
+
let(:remote) { 'origin' }
|
90
|
+
let(:branch) { 'master' }
|
91
|
+
|
92
|
+
context "when no arguments are given" do
|
93
|
+
it "must run a `git pull REMOTE BRANCH` command" do
|
94
|
+
expect(subject).to receive(:system).with(
|
95
|
+
'git', 'pull', remote, branch
|
96
|
+
).and_return(true)
|
97
|
+
|
98
|
+
subject.pull!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when a remote: argument is given" do
|
103
|
+
let(:remote) { 'other' }
|
104
|
+
|
105
|
+
it "must pass the `REMOTE` argument to the `git pull` command" do
|
106
|
+
expect(subject).to receive(:system).with(
|
107
|
+
'git', 'pull', remote, branch
|
108
|
+
).and_return(true)
|
109
|
+
|
110
|
+
subject.pull!(remote: remote)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when a branch: argument is given" do
|
115
|
+
let(:branch) { 'other_branch' }
|
116
|
+
|
117
|
+
it "must pass the `BRANCH` argument to the `git pull` command" do
|
118
|
+
expect(subject).to receive(:system).with(
|
119
|
+
'git', 'pull', remote, branch
|
120
|
+
).and_return(true)
|
121
|
+
|
122
|
+
subject.pull!(branch: branch)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when the `git pull` command succeeds" do
|
127
|
+
it "must return true" do
|
128
|
+
expect(subject).to receive(:system).with(
|
129
|
+
'git', 'pull', remote, branch
|
130
|
+
).and_return(true)
|
131
|
+
|
132
|
+
expect(subject.pull!).to eq(true)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when the `git pull` command fails" do
|
137
|
+
it do
|
138
|
+
expect(subject).to receive(:system).with(
|
139
|
+
'git', 'pull', remote, branch
|
140
|
+
).and_return(false)
|
141
|
+
|
142
|
+
expect {
|
143
|
+
subject.pull!
|
144
|
+
}.to raise_error(GitPullFailed)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when the repository is not a git repository" do
|
150
|
+
before { expect(subject).to receive(:git?).and_return(false) }
|
151
|
+
|
152
|
+
it "must return false" do
|
153
|
+
expect(subject.pull!).to eq(false)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "#has_year?" do
|
159
|
+
it "should test if a repository has a directory for the given year" do
|
160
|
+
expect(subject.has_year?('1999')).to eq(true)
|
161
|
+
end
|
162
|
+
|
163
|
+
context "when the given year does not exist in the repository" do
|
164
|
+
it "must return false" do
|
165
|
+
expect(subject.has_year?('3000')).to eq(false)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
let(:dirs) do
|
171
|
+
%w[
|
172
|
+
1999 2001 2003 2005 2007 2009 2011 2013 2015 2017 2019 2021
|
173
|
+
2000 2002 2004 2006 2008 2010 2012 2014 2016 2018 2020
|
174
|
+
]
|
175
|
+
end
|
176
|
+
let(:dir_paths) do
|
177
|
+
dirs.map { |dir| File.join(path,dir) }
|
178
|
+
end
|
179
|
+
|
180
|
+
let(:sorted_dirs) { dirs.sort }
|
181
|
+
let(:sorted_dir_paths) do
|
182
|
+
sorted_dirs.map { |dir| File.join(path,dir) }
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "#directories" do
|
186
|
+
subject { super().directories }
|
187
|
+
|
188
|
+
it "must find all year directories" do
|
189
|
+
expect(subject).to all(be =~ /\/[1-2][0-9]{3}$/)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "must return paths to all year directories within the repository" do
|
193
|
+
expect(subject).to match_array(dir_paths)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "must sort the year directories" do
|
197
|
+
expect(subject).to eq(sorted_dir_paths)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "#years" do
|
202
|
+
subject { super().years }
|
203
|
+
|
204
|
+
it do
|
205
|
+
expect(subject).to_not be_empty
|
206
|
+
expect(subject).to all(be_kind_of(YearDir))
|
207
|
+
end
|
208
|
+
|
209
|
+
it "must map the #directories to YearDir objects" do
|
210
|
+
expect(subject.map(&:path)).to eq(sorted_dir_paths)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "#year" do
|
215
|
+
let(:year_number) { '2001' }
|
216
|
+
|
217
|
+
subject { super().year(year_number) }
|
218
|
+
|
219
|
+
it "must return a YearDir object for the given year" do
|
220
|
+
expect(subject).to be_kind_of(YearDir)
|
221
|
+
expect(subject.path).to eq(File.join(path,year_number))
|
222
|
+
end
|
223
|
+
|
224
|
+
context "when the given year does not exist in the repository" do
|
225
|
+
let(:year_number) { '3000' }
|
226
|
+
|
227
|
+
it do
|
228
|
+
expect { subject }.to raise_error(YearDirNotFound)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
it { expect(described_class).to include(Enumerable) }
|
234
|
+
|
235
|
+
include_examples "CVE methods"
|
236
|
+
|
237
|
+
describe "#size" do
|
238
|
+
it "must match the total number of CVE .json files in the repository" do
|
239
|
+
expect(subject.size).to eq(
|
240
|
+
subject.years.reduce(0) { |i,year|
|
241
|
+
i + year.ranges.reduce(0) { |j,range|
|
242
|
+
j + range.files.length
|
243
|
+
}
|
244
|
+
}
|
245
|
+
)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|