cve_schema 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +28 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +26 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.md +50 -0
- data/Rakefile +23 -0
- data/benchmark.rb +47 -0
- data/cve_schema.gemspec +61 -0
- data/gemspec.yml +19 -0
- data/lib/cve_schema.rb +2 -0
- data/lib/cve_schema/cve.rb +257 -0
- data/lib/cve_schema/cve/affects.rb +55 -0
- data/lib/cve_schema/cve/configuration.rb +14 -0
- data/lib/cve_schema/cve/credit.rb +14 -0
- data/lib/cve_schema/cve/data_meta.rb +185 -0
- data/lib/cve_schema/cve/description.rb +24 -0
- data/lib/cve_schema/cve/exploit.rb +14 -0
- data/lib/cve_schema/cve/has_lang_value.rb +93 -0
- data/lib/cve_schema/cve/id.rb +79 -0
- data/lib/cve_schema/cve/impact.rb +75 -0
- data/lib/cve_schema/cve/impact/cvss_v2.rb +318 -0
- data/lib/cve_schema/cve/impact/cvss_v3.rb +388 -0
- data/lib/cve_schema/cve/na.rb +8 -0
- data/lib/cve_schema/cve/problem_type.rb +56 -0
- data/lib/cve_schema/cve/product.rb +79 -0
- data/lib/cve_schema/cve/reference.rb +82 -0
- data/lib/cve_schema/cve/solution.rb +14 -0
- data/lib/cve_schema/cve/source.rb +75 -0
- data/lib/cve_schema/cve/timeline.rb +65 -0
- data/lib/cve_schema/cve/timestamp.rb +25 -0
- data/lib/cve_schema/cve/vendor.rb +83 -0
- data/lib/cve_schema/cve/version.rb +126 -0
- data/lib/cve_schema/cve/work_around.rb +14 -0
- data/lib/cve_schema/exceptions.rb +20 -0
- data/lib/cve_schema/version.rb +6 -0
- data/spec/affects_spec.rb +28 -0
- data/spec/configuration_spec.rb +6 -0
- data/spec/credit_spec.rb +6 -0
- data/spec/cve_schema_spec.rb +8 -0
- data/spec/cve_spec.rb +414 -0
- data/spec/data_meta_spec.rb +167 -0
- data/spec/description.rb +24 -0
- data/spec/exploit_spec.rb +6 -0
- data/spec/fixtures/CVE-2020-1994.json +140 -0
- data/spec/fixtures/CVE-2020-2005.json +152 -0
- data/spec/fixtures/CVE-2020-2050.json +233 -0
- data/spec/fixtures/CVE-2020-4700.json +99 -0
- data/spec/has_lang_value_spec.rb +56 -0
- data/spec/id_spec.rb +91 -0
- data/spec/impact/cvss_v3_spec.rb +118 -0
- data/spec/impact_spec.rb +45 -0
- data/spec/na_spec.rb +14 -0
- data/spec/problem_type_spec.rb +26 -0
- data/spec/product_spec.rb +73 -0
- data/spec/reference_spec.rb +70 -0
- data/spec/shared_examples.rb +19 -0
- data/spec/solution_spec.rb +6 -0
- data/spec/source_spec.rb +84 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/timeline_spec.rb +86 -0
- data/spec/timestamp_spec.rb +24 -0
- data/spec/vendor_spec.rb +73 -0
- data/spec/version_spec.rb +104 -0
- data/spec/work_around_spec.rb +6 -0
- metadata +133 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples'
|
3
|
+
require 'cve_schema/cve/impact/cvss_v3'
|
4
|
+
|
5
|
+
describe CVESchema::CVE::Impact::CVSSv3 do
|
6
|
+
describe "#initialize" do
|
7
|
+
context "when given the bm: keyword" do
|
8
|
+
let(:bm) { double(:BM) }
|
9
|
+
|
10
|
+
subject { described_class.new(bm: bm) }
|
11
|
+
|
12
|
+
it "must set #bm" do
|
13
|
+
expect(subject.bm).to be(bm)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when given the tm: keyword" do
|
18
|
+
let(:tm) { double(:TM) }
|
19
|
+
|
20
|
+
subject { described_class.new(tm: tm) }
|
21
|
+
|
22
|
+
it "must set #tm" do
|
23
|
+
expect(subject.tm).to be(tm)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when given the em: keyword" do
|
28
|
+
let(:em) { double(:EM) }
|
29
|
+
|
30
|
+
subject { described_class.new(em: em) }
|
31
|
+
|
32
|
+
it "must set #em" do
|
33
|
+
expect(subject.em).to be(em)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe ".load" do
|
39
|
+
include_examples ".load"
|
40
|
+
|
41
|
+
let(:cve_id) { 'CVE-2020-4700' }
|
42
|
+
let(:json_node) { json_tree['impact']['cvssv3'] }
|
43
|
+
|
44
|
+
context '"BM":' do
|
45
|
+
it { expect(subject.bm).to be_kind_of(described_class::BM) }
|
46
|
+
end
|
47
|
+
|
48
|
+
context '"TM":' do
|
49
|
+
it { expect(subject.bm).to be_kind_of(described_class::BM) }
|
50
|
+
end
|
51
|
+
|
52
|
+
context '"EM":' do
|
53
|
+
pending 'need to find a CVE containing "EM":' do
|
54
|
+
it { expect(subject.bm).to be_kind_of(described_class::BM) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe described_class::BM do
|
60
|
+
describe "#initialize" do
|
61
|
+
end
|
62
|
+
|
63
|
+
describe ".load" do
|
64
|
+
include_examples ".load"
|
65
|
+
|
66
|
+
let(:cve_id) { 'CVE-2020-4700' }
|
67
|
+
let(:json_node) { json_tree['impact']['cvssv3']['BM'] }
|
68
|
+
|
69
|
+
{'AV' => :av, 'AC' => :ac, 'PR' => :pr, 'UI' => :ui, 'S' => :s, 'C' => :c, 'I' => :i, 'A' => :a}.each do |json_key,attr|
|
70
|
+
context "\"#{json_key}\":" do
|
71
|
+
it "must set ##{attr}" do
|
72
|
+
expect(subject.send(attr)).to eq(json_node[json_key].to_sym)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context '"SCORE":' do
|
78
|
+
it "must set #score" do
|
79
|
+
expect(subject.score).to eq(json_node['SCORE'])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe described_class::TM do
|
86
|
+
describe "#initialize" do
|
87
|
+
end
|
88
|
+
|
89
|
+
describe ".load" do
|
90
|
+
include_examples ".load"
|
91
|
+
|
92
|
+
let(:cve_id) { 'CVE-2020-4700' }
|
93
|
+
let(:json_node) { json_tree['impact']['cvssv3']['TM'] }
|
94
|
+
|
95
|
+
{'E' => :e, 'RL' => :rl, 'RC' => :rc}.each do |json_key,attr|
|
96
|
+
context "\"#{json_key}\":" do
|
97
|
+
it "must set ##{attr}" do
|
98
|
+
expect(subject.send(attr)).to eq(json_node[json_key].to_sym)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe described_class::EM do
|
106
|
+
describe "#initialize" do
|
107
|
+
end
|
108
|
+
|
109
|
+
describe ".load" do
|
110
|
+
include_examples ".load"
|
111
|
+
|
112
|
+
let(:cve_id) { 'CVE-2020-4700' }
|
113
|
+
let(:json_node) { json_tree['impact']['cvssv3']['EM'] }
|
114
|
+
|
115
|
+
pending 'need to find a CVE containing "EM":'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/impact_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples'
|
3
|
+
require 'cve_schema/cve/impact'
|
4
|
+
|
5
|
+
describe CVESchema::CVE::Impact do
|
6
|
+
describe "#initialize" do
|
7
|
+
context "when cvss_v2: is given" do
|
8
|
+
let(:cvssv2) { double(:CVSSv2) }
|
9
|
+
|
10
|
+
subject { described_class.new(cvssv2: cvssv2) }
|
11
|
+
|
12
|
+
it "must set #cvssv2" do
|
13
|
+
expect(subject.cvss_v2).to be(cvssv2)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when cvssv3: is given" do
|
18
|
+
let(:cvssv3) { double(:CVSSv3) }
|
19
|
+
|
20
|
+
subject { described_class.new(cvssv3: cvssv3) }
|
21
|
+
|
22
|
+
it "must set #cvss_v3" do
|
23
|
+
expect(subject.cvss_v3).to be(cvssv3)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".load" do
|
29
|
+
include_examples ".load"
|
30
|
+
|
31
|
+
let(:json_node) { json_tree['impact'] }
|
32
|
+
|
33
|
+
context '"cvssv2":' do
|
34
|
+
pending 'need to find a CVE with a "cvssv2": key' do
|
35
|
+
it { expect(subject.cvssv2).to be_kind_of(described_class::CVSSv2) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context '"cvssv3":' do
|
40
|
+
let(:cve_id) { 'CVE-2020-4700' }
|
41
|
+
|
42
|
+
it { expect(subject.cvssv3).to be_kind_of(described_class::CVSSv3) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/na_spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cve_schema/cve/na'
|
3
|
+
|
4
|
+
describe "CVESchema::CVE::NA" do
|
5
|
+
subject { CVESchema::CVE::NA }
|
6
|
+
|
7
|
+
it "must equal 'n/a'" do
|
8
|
+
expect(subject).to eq('n/a')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "must be froozen" do
|
12
|
+
expect(subject).to be_frozen
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples'
|
3
|
+
require 'cve_schema/cve/problem_type'
|
4
|
+
|
5
|
+
describe CVESchema::CVE::ProblemType do
|
6
|
+
describe "#initialize" do
|
7
|
+
let(:description) { double(:description) }
|
8
|
+
|
9
|
+
subject { described_class.new(description) }
|
10
|
+
|
11
|
+
it "must set #description" do
|
12
|
+
expect(subject.description).to be(description)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".load" do
|
17
|
+
include_examples ".load"
|
18
|
+
|
19
|
+
let(:json_node) { json_tree['problemtype']['problemtype_data'][0] }
|
20
|
+
|
21
|
+
context '"description":' do
|
22
|
+
it { expect(subject.description).to_not be_empty }
|
23
|
+
it { expect(subject.description).to all(be_kind_of(CVESchema::CVE::Description)) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples'
|
3
|
+
require 'cve_schema/cve/product'
|
4
|
+
|
5
|
+
describe CVESchema::CVE::Product do
|
6
|
+
let(:product_name) { 'Example' }
|
7
|
+
let(:version) { ['1.2.3', '2.0.0'] }
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
describe "required keywords" do
|
11
|
+
it "must require a product_name:" do
|
12
|
+
expect {
|
13
|
+
described_class.new(version: version)
|
14
|
+
}.to raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when a product_name: keyword is given" do
|
19
|
+
subject { described_class.new(product_name: product_name) }
|
20
|
+
|
21
|
+
it "must set #product_name" do
|
22
|
+
expect(subject.product_name).to eq(product_name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when a verisons: keyword is given" do
|
27
|
+
subject do
|
28
|
+
described_class.new(product_name: product_name, version: version)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must set #product_name" do
|
32
|
+
expect(subject.version).to eq(version)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".load" do
|
38
|
+
include_examples ".load"
|
39
|
+
|
40
|
+
let(:json_node) do
|
41
|
+
json_tree['affects']['vendor']['vendor_data'][0]['product']['product_data'][0]
|
42
|
+
end
|
43
|
+
|
44
|
+
context '"product_name":' do
|
45
|
+
it "must set #product_name" do
|
46
|
+
expect(subject.product_name).to eq(json_node['product_name'])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context '"version":' do
|
51
|
+
it { expect(subject.version).to_not be_empty }
|
52
|
+
it { expect(subject.version).to all(be_kind_of(CVESchema::CVE::Version)) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#na?" do
|
57
|
+
subject do
|
58
|
+
described_class.new(product_name: product_name, version: version)
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when value is 'n/a'" do
|
62
|
+
let(:product_name) { 'n/a' }
|
63
|
+
|
64
|
+
it { expect(subject.na?).to be(true) }
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when value is not 'n/a'" do
|
68
|
+
let(:product_name) { 'foo' }
|
69
|
+
|
70
|
+
it { expect(subject.na?).to be(false) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples'
|
3
|
+
require 'cve_schema/cve/reference'
|
4
|
+
|
5
|
+
describe CVESchema::CVE::Reference do
|
6
|
+
describe "#initialize" do
|
7
|
+
let(:url) { 'https://example.com/foo.html' }
|
8
|
+
let(:name) { 'foo' }
|
9
|
+
let(:refsource) { :MISC }
|
10
|
+
|
11
|
+
context "required keywords" do
|
12
|
+
context "when the url: keyword is not given" do
|
13
|
+
it do
|
14
|
+
expect {
|
15
|
+
described_class.new(name: name, refsource: refsource)
|
16
|
+
}.to raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
subject { described_class.new(url: url) }
|
22
|
+
|
23
|
+
it "must set #url" do
|
24
|
+
expect(subject.url).to be(url)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the name: keyword is given" do
|
28
|
+
subject { described_class.new(url: url, name: name) }
|
29
|
+
|
30
|
+
it "must set #name" do
|
31
|
+
expect(subject.name).to be(name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when the refsource: keyword is given" do
|
36
|
+
subject { described_class.new(url: url, refsource: refsource) }
|
37
|
+
|
38
|
+
it "must set #refsource" do
|
39
|
+
expect(subject.refsource).to be(refsource)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".load" do
|
45
|
+
include_examples ".load"
|
46
|
+
|
47
|
+
let(:json_node) { json_tree['references']['reference_data'][0] }
|
48
|
+
|
49
|
+
context '"refsource":' do
|
50
|
+
let(:json_value) { json_node['refsource'] }
|
51
|
+
let(:expected) { json_value.to_sym }
|
52
|
+
|
53
|
+
it 'must parse the "refsource": value and set #refsource' do
|
54
|
+
expect(subject.refsource).to eq(expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context '"url":' do
|
59
|
+
it "muset set #url" do
|
60
|
+
expect(subject.url).to eq(json_node['url'])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context '"name":' do
|
65
|
+
it "must set #name" do
|
66
|
+
expect(subject.name).to eq(json_node['name'])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
RSpec.shared_examples ".from_json" do
|
6
|
+
let(:cve_id) { 'CVE-2020-1994' }
|
7
|
+
let(:file) { File.expand_path("../fixtures/#{cve_id}.json",__FILE__) }
|
8
|
+
|
9
|
+
let(:json_tree) { JSON.parse(File.read(file)) }
|
10
|
+
let(:json_node) { json_tree }
|
11
|
+
|
12
|
+
subject { described_class.from_json(json_node) }
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.shared_examples ".load" do
|
16
|
+
include_examples ".from_json"
|
17
|
+
|
18
|
+
subject { described_class.load(json_node) }
|
19
|
+
end
|
data/spec/source_spec.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_examples'
|
3
|
+
require 'cve_schema/cve/source'
|
4
|
+
|
5
|
+
describe CVESchema::CVE::Source do
|
6
|
+
describe "#initialize" do
|
7
|
+
let(:defect) { ['PAN-123391'] }
|
8
|
+
let(:discovery) { :USER }
|
9
|
+
let(:advisory) { 'VENDOR-12345' }
|
10
|
+
|
11
|
+
context "required keywords" do
|
12
|
+
context "when the discovery: keyword is not given" do
|
13
|
+
it do
|
14
|
+
expect {
|
15
|
+
described_class.new(defect: defect, advisory: advisory)
|
16
|
+
}.to raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
subject do
|
22
|
+
described_class.new(discovery: discovery)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "must set #discovery" do
|
26
|
+
expect(subject.discovery).to be(discovery)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when the defect: keyword is given" do
|
30
|
+
subject do
|
31
|
+
described_class.new(
|
32
|
+
discovery: discovery,
|
33
|
+
defect: defect
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "must set #defect" do
|
38
|
+
expect(subject.defect).to be(defect)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when the advisory: keyword is given" do
|
43
|
+
subject do
|
44
|
+
described_class.new(
|
45
|
+
discovery: discovery,
|
46
|
+
advisory: advisory
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "must set #advisory" do
|
51
|
+
expect(subject.advisory).to be(advisory)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".load" do
|
57
|
+
include_examples ".load"
|
58
|
+
|
59
|
+
let(:json_node) { json_tree['source'] }
|
60
|
+
|
61
|
+
context '"defect":' do
|
62
|
+
it "must set #defect" do
|
63
|
+
expect(subject.defect).to eq(json_node['defect'])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context '"discovery":' do
|
68
|
+
let(:json_value) { json_node['discovery'] }
|
69
|
+
let(:expected) { json_value.to_sym }
|
70
|
+
|
71
|
+
it "must set #discovery" do
|
72
|
+
expect(subject.discovery).to eq(expected.to_sym)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context '"advisory":' do
|
77
|
+
pending 'need to find a CVE with the "advisory": key' do
|
78
|
+
it "must set #advisory" do
|
79
|
+
expect(subject.advisory).to eq(json_node['advisory'])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|