cve_schema 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 +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,56 @@
|
|
1
|
+
require 'cve_schema/cve/description'
|
2
|
+
|
3
|
+
module CVESchema
|
4
|
+
class CVE
|
5
|
+
#
|
6
|
+
# Represents an element within the `"problemtype_data"` JSON Array.
|
7
|
+
#
|
8
|
+
class ProblemType
|
9
|
+
|
10
|
+
# @return [Array<Description>]
|
11
|
+
attr_reader :description
|
12
|
+
|
13
|
+
alias descriptions description
|
14
|
+
|
15
|
+
#
|
16
|
+
# Initializes the problem-type object.
|
17
|
+
#
|
18
|
+
# @param [Array<Description>] description
|
19
|
+
#
|
20
|
+
def initialize(description)
|
21
|
+
@description = description
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Maps the parsed JSON to an Array of {Description} objects for
|
26
|
+
# {#initialize}.
|
27
|
+
#
|
28
|
+
# @param [Hash{String => Object}] json
|
29
|
+
# The parsed JSON.
|
30
|
+
#
|
31
|
+
# @return [Array<Description>]
|
32
|
+
#
|
33
|
+
# @api semipublic
|
34
|
+
#
|
35
|
+
def self.from_json(json)
|
36
|
+
json['description'].map(&Description.method(:load))
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Loads the problem-type object from parsed JSON.
|
41
|
+
#
|
42
|
+
# @param [Hash{String => Object}] json
|
43
|
+
# The parsed JSON.
|
44
|
+
#
|
45
|
+
# @return [ProblemType]
|
46
|
+
# The loaded problem-type object.
|
47
|
+
#
|
48
|
+
# @api semipublic
|
49
|
+
#
|
50
|
+
def self.load(json)
|
51
|
+
new(from_json(json))
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'cve_schema/cve/version'
|
2
|
+
require 'cve_schema/cve/na'
|
3
|
+
|
4
|
+
module CVESchema
|
5
|
+
class CVE
|
6
|
+
#
|
7
|
+
# Represents a product element within the `"product_data"` JSON Array.
|
8
|
+
#
|
9
|
+
class Product
|
10
|
+
|
11
|
+
# The product name.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :product_name
|
15
|
+
|
16
|
+
# The list of affected versions.
|
17
|
+
#
|
18
|
+
# @return [Array<Version>]
|
19
|
+
attr_reader :version
|
20
|
+
|
21
|
+
alias versions version
|
22
|
+
|
23
|
+
#
|
24
|
+
# Initializes the product.
|
25
|
+
#
|
26
|
+
# @param [String] product_name
|
27
|
+
#
|
28
|
+
# @param [Array<Version>] version
|
29
|
+
#
|
30
|
+
def initialize(product_name: , version: [])
|
31
|
+
@product_name = product_name
|
32
|
+
@version = version
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Determines if the {#product_name} is `n/a`.
|
37
|
+
#
|
38
|
+
# @return [Boolean]
|
39
|
+
#
|
40
|
+
def na?
|
41
|
+
@product_name == NA
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
46
|
+
#
|
47
|
+
# @param [Hash{String => Object}] json
|
48
|
+
# The parsed JSON.
|
49
|
+
#
|
50
|
+
# @return [Hash{Symbol => Object}]
|
51
|
+
# The mapped Symbol Hash.
|
52
|
+
#
|
53
|
+
# @api semipublic
|
54
|
+
#
|
55
|
+
def self.from_json(json)
|
56
|
+
{
|
57
|
+
product_name: json['product_name'],
|
58
|
+
version: Array(json['version']['version_data']).map(&Version.method(:load))
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Loads the product object from parsed JSON.
|
64
|
+
#
|
65
|
+
# @param [Hash{String => Object}] json
|
66
|
+
# The parsed JSON.
|
67
|
+
#
|
68
|
+
# @return [Product]
|
69
|
+
# The loaded product.
|
70
|
+
#
|
71
|
+
# @api semipublic
|
72
|
+
#
|
73
|
+
def self.load(json)
|
74
|
+
new(**from_json(json))
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CVESchema
|
4
|
+
class CVE
|
5
|
+
#
|
6
|
+
# Represents a reference object within the `"reference_data"` JSON Array.
|
7
|
+
#
|
8
|
+
class Reference
|
9
|
+
|
10
|
+
# Reference URL.
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
attr_reader :url
|
14
|
+
|
15
|
+
# Optional reference name.
|
16
|
+
#
|
17
|
+
# @return [String, nil]
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
REFSOURCES = {
|
21
|
+
'MISC' => :MISC
|
22
|
+
}
|
23
|
+
REFSOURCES.default_proc = proc { |hash,key| key }
|
24
|
+
|
25
|
+
# Optional reference source identifier.
|
26
|
+
#
|
27
|
+
# @return [:MISC, String, nil]
|
28
|
+
attr_reader :refsource
|
29
|
+
|
30
|
+
alias ref_source refsource
|
31
|
+
|
32
|
+
#
|
33
|
+
# Initializes the reference.
|
34
|
+
#
|
35
|
+
# @param [String] url
|
36
|
+
#
|
37
|
+
# @param [nil, String] name
|
38
|
+
#
|
39
|
+
# @param [nil, :MISC, String] refsource
|
40
|
+
#
|
41
|
+
def initialize(url: , name: nil, refsource: nil)
|
42
|
+
@url = url
|
43
|
+
@name = name
|
44
|
+
@refsource = refsource
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
49
|
+
#
|
50
|
+
# @param [Hash{String => Object}] json
|
51
|
+
# The parsed JSON.
|
52
|
+
#
|
53
|
+
# @return [Hash{Symbol => Object}]
|
54
|
+
# The mapped Symbol Hash.
|
55
|
+
#
|
56
|
+
# @api semipublic
|
57
|
+
#
|
58
|
+
def self.from_json(json)
|
59
|
+
{
|
60
|
+
url: json['url'],
|
61
|
+
name: json['name'],
|
62
|
+
refsource: REFSOURCES[json['refsource']]
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Loads the reference from the parsed JSON.
|
68
|
+
#
|
69
|
+
# @param [Hash{String => Object}] json
|
70
|
+
# The parsed JSON.
|
71
|
+
#
|
72
|
+
# @return [Reference]
|
73
|
+
#
|
74
|
+
# @api semipublic
|
75
|
+
#
|
76
|
+
def self.load(json)
|
77
|
+
new(**from_json(json))
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CVESchema
|
4
|
+
class CVE
|
5
|
+
#
|
6
|
+
# Represents the `"source"` JSON object.
|
7
|
+
#
|
8
|
+
class Source
|
9
|
+
|
10
|
+
# @return [Array<String>, nil]
|
11
|
+
attr_reader :defect
|
12
|
+
|
13
|
+
DISCOVERY = {
|
14
|
+
'INTERNAL' => :INTERNAL,
|
15
|
+
'EXTERNAL' => :EXTERNAL,
|
16
|
+
'USER' => :USER,
|
17
|
+
'UNKNOWN' => :UNKNOWN
|
18
|
+
}
|
19
|
+
|
20
|
+
# @return [:INTERNAL, :EXTERNAL, :USER, :UNKNOWN]
|
21
|
+
attr_reader :discovery
|
22
|
+
|
23
|
+
# @return [String, nil]
|
24
|
+
attr_reader :advisory
|
25
|
+
|
26
|
+
#
|
27
|
+
# Initializes the source object.
|
28
|
+
#
|
29
|
+
# @param [Array<String>, nil] defect
|
30
|
+
#
|
31
|
+
# @param [:INTERNAL, :EXTERNAL, :USER, :UNKNOWN] discovery
|
32
|
+
#
|
33
|
+
# @param [String, nil] advisory
|
34
|
+
#
|
35
|
+
def initialize(discovery: , defect: nil, advisory: nil)
|
36
|
+
@defect = defect
|
37
|
+
@discovery = discovery
|
38
|
+
@advisory = advisory
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
43
|
+
#
|
44
|
+
# @param [Hash{String => Object}] json
|
45
|
+
# The parsed JSON.
|
46
|
+
#
|
47
|
+
# @return [Hash{Symbol => Object}]
|
48
|
+
# The mapped Symbol Hash.
|
49
|
+
#
|
50
|
+
def self.from_json(json)
|
51
|
+
{
|
52
|
+
defect: json['defect'],
|
53
|
+
discovery: DISCOVERY[json['discovery']],
|
54
|
+
advisory: json['advisory']
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Loads the source from the parsed JSON.
|
60
|
+
#
|
61
|
+
# @param [Hash{String => Object}] json
|
62
|
+
# The parsed JSON.
|
63
|
+
#
|
64
|
+
# @return [Source]
|
65
|
+
# The loaded source object.
|
66
|
+
#
|
67
|
+
# @api semipublic
|
68
|
+
#
|
69
|
+
def self.load(json)
|
70
|
+
new(**from_json(json))
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'cve_schema/cve/timestamp'
|
2
|
+
require 'cve_schema/cve/has_lang_value'
|
3
|
+
|
4
|
+
module CVESchema
|
5
|
+
class CVE
|
6
|
+
#
|
7
|
+
# Represents a timeline entry in the `"timeline"` JSON Array.
|
8
|
+
#
|
9
|
+
class Timeline
|
10
|
+
|
11
|
+
include HasLangValue
|
12
|
+
|
13
|
+
# The time of the timeline event.
|
14
|
+
#
|
15
|
+
# @return [DateTime]
|
16
|
+
attr_reader :time
|
17
|
+
|
18
|
+
#
|
19
|
+
# Initializes the timeline object.
|
20
|
+
#
|
21
|
+
# @param [DateTime] time
|
22
|
+
#
|
23
|
+
def initialize(time: , **kargs)
|
24
|
+
super(**kargs)
|
25
|
+
|
26
|
+
@time = time
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
31
|
+
#
|
32
|
+
# @param [Hash{String => Object}] json
|
33
|
+
# The parsed JSON.
|
34
|
+
#
|
35
|
+
# @return [Hash{Symbol => Object}]
|
36
|
+
# The mapped Symbol Hash.
|
37
|
+
#
|
38
|
+
# @api semipublic
|
39
|
+
#
|
40
|
+
def self.from_json(json)
|
41
|
+
{
|
42
|
+
lang: json['lang'],
|
43
|
+
time: Timestamp.parse(json['time']),
|
44
|
+
value: json['value']
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Loads the timeline object from the parsed JSON.
|
50
|
+
#
|
51
|
+
# @param [Hash{String => Object}] json
|
52
|
+
# The parsed JSON.
|
53
|
+
#
|
54
|
+
# @return [Timeline]
|
55
|
+
# The loaded timeline object.
|
56
|
+
#
|
57
|
+
# @api semipublic
|
58
|
+
#
|
59
|
+
def self.load(json)
|
60
|
+
new(**from_json(json))
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'cve_schema/exceptions'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module CVESchema
|
5
|
+
class CVE
|
6
|
+
module Timestamp
|
7
|
+
#
|
8
|
+
# Parses a CVE timestamp (ISO 8601).
|
9
|
+
#
|
10
|
+
# @param [String] timestamp
|
11
|
+
# The raw timestamp String.
|
12
|
+
#
|
13
|
+
# @return [DateTime]
|
14
|
+
# The parsed ISO 8601 timestamp.
|
15
|
+
#
|
16
|
+
# @see https://github.com/CVEProject/cve-schema/blob/master/schema/v4.0/DRAFT-JSON-file-format-v4.md#timestamps
|
17
|
+
#
|
18
|
+
def self.parse(timestamp)
|
19
|
+
DateTime.iso8601(timestamp)
|
20
|
+
rescue Date::Error
|
21
|
+
raise InvalidJSON.new("invalid ISO-8601 timestamp: #{timestamp.inspect}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'cve_schema/cve/product'
|
2
|
+
require 'cve_schema/cve/na'
|
3
|
+
|
4
|
+
module CVESchema
|
5
|
+
class CVE
|
6
|
+
#
|
7
|
+
# Represents an element within the `"vendor_data"` JSON Array.
|
8
|
+
#
|
9
|
+
class Vendor
|
10
|
+
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :vendor_name
|
13
|
+
|
14
|
+
# @return [Array<Product>]
|
15
|
+
attr_reader :product
|
16
|
+
|
17
|
+
#
|
18
|
+
# Initializes the vendor object.
|
19
|
+
#
|
20
|
+
# @param [String] vendor_name
|
21
|
+
#
|
22
|
+
# @param [Array<Product>] product
|
23
|
+
#
|
24
|
+
def initialize(vendor_name: , product: )
|
25
|
+
@vendor_name = vendor_name
|
26
|
+
@product = product
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Determines if the {#vendor_name} is `n/a`.
|
31
|
+
#
|
32
|
+
# @return [Boolean]
|
33
|
+
#
|
34
|
+
def na?
|
35
|
+
@vendor_name == NA
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Converts the vendor object to a String.
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
# The vendor name
|
43
|
+
#
|
44
|
+
def to_s
|
45
|
+
@vendor_name
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
50
|
+
#
|
51
|
+
# @param [Hash{String => Object}] json
|
52
|
+
# The parsed JSON.
|
53
|
+
#
|
54
|
+
# @return [Hash{Symbol => Object}]
|
55
|
+
# The mapped Symbol Hash.
|
56
|
+
#
|
57
|
+
# @api semipublic
|
58
|
+
#
|
59
|
+
def self.from_json(json)
|
60
|
+
{
|
61
|
+
vendor_name: json['vendor_name'],
|
62
|
+
product: json['product']['product_data'].map(&Product.method(:load))
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Loads the vendor object from the parsed JSON.
|
68
|
+
#
|
69
|
+
# @param [Hash{String => Object}] json
|
70
|
+
# The parsed JSON.
|
71
|
+
#
|
72
|
+
# @return [Vendor]
|
73
|
+
# The loaded vendor object.
|
74
|
+
#
|
75
|
+
# @api semipublic
|
76
|
+
#
|
77
|
+
def self.load(json)
|
78
|
+
new(**from_json(json))
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|