nvd-json_feeds 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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.github/workflows/ruby.yml +29 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +25 -0
  8. data/Gemfile +13 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +136 -0
  11. data/Rakefile +31 -0
  12. data/gemspec.yml +22 -0
  13. data/lib/nvd/json_feeds.rb +25 -0
  14. data/lib/nvd/json_feeds/exceptions.rb +15 -0
  15. data/lib/nvd/json_feeds/feed.rb +50 -0
  16. data/lib/nvd/json_feeds/feed_file.rb +95 -0
  17. data/lib/nvd/json_feeds/feed_uri.rb +131 -0
  18. data/lib/nvd/json_feeds/gz_feed_file.rb +60 -0
  19. data/lib/nvd/json_feeds/gz_feed_uri.rb +25 -0
  20. data/lib/nvd/json_feeds/json_feed_file.rb +21 -0
  21. data/lib/nvd/json_feeds/meta.rb +122 -0
  22. data/lib/nvd/json_feeds/meta_feed_uri.rb +22 -0
  23. data/lib/nvd/json_feeds/schema/configurations.rb +61 -0
  24. data/lib/nvd/json_feeds/schema/configurations/node.rb +98 -0
  25. data/lib/nvd/json_feeds/schema/cpe/has_uri.rb +66 -0
  26. data/lib/nvd/json_feeds/schema/cpe/match.rb +117 -0
  27. data/lib/nvd/json_feeds/schema/cpe/name.rb +67 -0
  28. data/lib/nvd/json_feeds/schema/cve_feed.rb +142 -0
  29. data/lib/nvd/json_feeds/schema/cve_item.rb +94 -0
  30. data/lib/nvd/json_feeds/schema/cvss_v2.rb +298 -0
  31. data/lib/nvd/json_feeds/schema/cvss_v3.rb +332 -0
  32. data/lib/nvd/json_feeds/schema/has_data_version.rb +54 -0
  33. data/lib/nvd/json_feeds/schema/impact.rb +73 -0
  34. data/lib/nvd/json_feeds/schema/impact/base_metric_v2.rb +132 -0
  35. data/lib/nvd/json_feeds/schema/impact/base_metric_v3.rb +79 -0
  36. data/lib/nvd/json_feeds/schema/timestamp.rb +9 -0
  37. data/lib/nvd/json_feeds/version.rb +6 -0
  38. data/lib/nvd/json_feeds/zip_feed_file.rb +64 -0
  39. data/lib/nvd/json_feeds/zip_feed_uri.rb +25 -0
  40. data/nvd-json_feeds.gemspec +61 -0
  41. data/spec/feed_file_examples.rb +27 -0
  42. data/spec/feed_file_spec.rb +42 -0
  43. data/spec/feed_spec.rb +56 -0
  44. data/spec/feed_uri_spec.rb +81 -0
  45. data/spec/fixtures/gz_feed_file/nvdcve-1.1-recent.json.gz +0 -0
  46. data/spec/fixtures/nvdcve-1.1-recent.json +180 -0
  47. data/spec/fixtures/zip_feed_file/nvdcve-1.1-recent.json.zip +0 -0
  48. data/spec/gz_feed_file_spec.rb +66 -0
  49. data/spec/gz_feed_uri_spec.rb +35 -0
  50. data/spec/json_feed_file_spec.rb +18 -0
  51. data/spec/json_feeds_spec.rb +8 -0
  52. data/spec/meta_spec.rb +141 -0
  53. data/spec/schema/configurations/node_spec.rb +87 -0
  54. data/spec/schema/configurations_spec.rb +57 -0
  55. data/spec/schema/cpe/match_spec.rb +188 -0
  56. data/spec/schema/cpe/name_spec.rb +54 -0
  57. data/spec/schema/cve_feed_spec.rb +162 -0
  58. data/spec/schema/cve_item_spec.rb +116 -0
  59. data/spec/schema/impact/base_metric_v2_spec.rb +183 -0
  60. data/spec/schema/impact/base_metric_v3_spec.rb +80 -0
  61. data/spec/schema/impact_spec.rb +53 -0
  62. data/spec/schema/shared_examples.rb +136 -0
  63. data/spec/schema/timestamp_spec.rb +8 -0
  64. data/spec/spec_helper.rb +8 -0
  65. data/spec/zip_feed_file_spec.rb +66 -0
  66. data/spec/zip_feed_uri_spec.rb +35 -0
  67. metadata +156 -0
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'nvd/json_feeds/version'
14
+ NVD::JSONFeeds::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = Array(gemspec['requirements'])
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
53
+ end
54
+ end
55
+
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.shared_examples_for "FeedFile" do
4
+ describe "#read" do
5
+ subject { super().read }
6
+
7
+ it "must return a String" do
8
+ expect(subject).to be_kind_of(String)
9
+ expect(subject).to_not be_empty
10
+ end
11
+ end
12
+
13
+ describe "#json" do
14
+ subject { super().json }
15
+
16
+ it "must return a parsed JSON Hash" do
17
+ expect(subject).to be_kind_of(Hash)
18
+ expect(subject).to_not be_empty
19
+ end
20
+ end
21
+
22
+ describe "#parse" do
23
+ it "must return a CVEFeed object" do
24
+ expect(subject.parse).to be_kind_of(Schema::CVEFeed)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'nvd/json_feeds/feed_file'
3
+
4
+ describe FeedFile do
5
+ let(:fixtures_dir) { File.expand_path('../fixtures',__FILE__) }
6
+ let(:filename) { 'nvdcve-1.1-recent.json' }
7
+ let(:path) { File.join(fixtures_dir,filename) }
8
+
9
+ subject { described_class.new(path) }
10
+
11
+ describe "#initialize" do
12
+ it "must set #path" do
13
+ expect(subject.path).to eq(path)
14
+ end
15
+
16
+ context "when given a relative path" do
17
+ let(:path) { File.join('../fixtures',filename) }
18
+
19
+ it "must expand the relative path" do
20
+ expect(subject.path).to eq(File.expand_path(path))
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#read" do
26
+ it do
27
+ expect { subject.read }.to raise_error(NotImplementedError)
28
+ end
29
+ end
30
+
31
+ describe "#to_s" do
32
+ it "must the #path" do
33
+ expect(subject.to_s).to eq(subject.path)
34
+ end
35
+ end
36
+
37
+ describe "#inspect" do
38
+ it "must include the class name and path" do
39
+ expect(subject.inspect).to eq("#<#{described_class}: #{subject.path}>")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'nvd/json_feeds/feed'
3
+
4
+ describe Feed do
5
+ let(:name) { :recent }
6
+
7
+ subject { described_class.new(name) }
8
+
9
+ describe "#initialize" do
10
+ it "must set #name" do
11
+ expect(subject.name).to eq(name)
12
+ end
13
+
14
+ describe "#meta" do
15
+ subject { super().meta }
16
+
17
+ it { expect(subject).to be_kind_of(MetaFeedURI) }
18
+
19
+ it "must have the same name" do
20
+ expect(subject.name).to eq(name)
21
+ end
22
+
23
+ it "must use '.meta' for the extension" do
24
+ expect(subject.ext).to eq('.meta')
25
+ end
26
+ end
27
+
28
+ describe "#gz" do
29
+ subject { super().gz }
30
+
31
+ it { expect(subject).to be_kind_of(GzFeedURI) }
32
+
33
+ it "must have the same name" do
34
+ expect(subject.name).to eq(name)
35
+ end
36
+
37
+ it "must use '.json.gz' for the extension" do
38
+ expect(subject.ext).to eq('.json.gz')
39
+ end
40
+ end
41
+
42
+ describe "#zip" do
43
+ subject { super().zip }
44
+
45
+ it { expect(subject).to be_kind_of(ZipFeedURI) }
46
+
47
+ it "must have the same name" do
48
+ expect(subject.name).to eq(name)
49
+ end
50
+
51
+ it "must use '.json.zip' for the extension" do
52
+ expect(subject.ext).to eq('.json.zip')
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'nvd/json_feeds/feed_uri'
3
+
4
+ describe FeedURI do
5
+ let(:name) { :recent }
6
+ let(:ext) { '.json.gz' }
7
+
8
+ subject { described_class.new(name,ext) }
9
+
10
+ describe "#initialize" do
11
+ it "must set #name" do
12
+ expect(subject.name).to eq(name)
13
+ end
14
+
15
+ it "must set #ext" do
16
+ expect(subject.ext).to eq(ext)
17
+ end
18
+
19
+ it "must set #filename" do
20
+ expect(subject.filename).to eq("nvdcve-1.1-#{name}#{ext}")
21
+ end
22
+ end
23
+
24
+ describe "#get", :integration do
25
+ let(:contents) { Net::HTTP.get(subject.uri) }
26
+
27
+ context "when not given a block" do
28
+ it "must return the full String of the file" do
29
+ expect(subject.get).to eq(contents)
30
+ end
31
+ end
32
+
33
+ context "when given a block" do
34
+ it "must yield each chunk of the file" do
35
+ chunks = []
36
+
37
+ subject.get { |chunk| chunks << chunk }
38
+
39
+ expect(chunks.join).to eq(contents)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#download", :integration do
45
+ context "when given a file" do
46
+ it "must return the path to the newly downloaded file" do
47
+ end
48
+ end
49
+
50
+ context "when given a directory" do
51
+ it "must return the path to the newly downloaded file in the directory" do
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "#uri" do
57
+ subject { super().uri }
58
+
59
+ it { expect(subject).to be_kind_of(URI::HTTPS) }
60
+
61
+ describe "host" do
62
+ it { expect(subject.host).to eq('nvd.nist.gov') }
63
+ end
64
+
65
+ describe "path" do
66
+ it { expect(subject.path).to start_with('/feeds/json/cve/1.1/') }
67
+ end
68
+ end
69
+
70
+ describe "#to_s" do
71
+ it "must the String version of the URI" do
72
+ expect(subject.to_s).to eq(subject.uri.to_s)
73
+ end
74
+ end
75
+
76
+ describe "#inspect" do
77
+ it "must include the class name and URI" do
78
+ expect(subject.inspect).to eq("#<#{described_class}: #{subject.uri}>")
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,180 @@
1
+ {
2
+ "CVE_data_type" : "CVE",
3
+ "CVE_data_format" : "MITRE",
4
+ "CVE_data_version" : "4.0",
5
+ "CVE_data_numberOfCVEs" : "343",
6
+ "CVE_data_timestamp" : "2020-12-30T11:00Z",
7
+ "CVE_Items" : [ {
8
+ "cve" : {
9
+ "data_type" : "CVE",
10
+ "data_format" : "MITRE",
11
+ "data_version" : "4.0",
12
+ "CVE_data_meta" : {
13
+ "ID" : "CVE-2018-1000891",
14
+ "ASSIGNER" : "cve@mitre.org"
15
+ },
16
+ "problemtype" : {
17
+ "problemtype_data" : [ {
18
+ "description" : [ {
19
+ "lang" : "en",
20
+ "value" : "CWE-400"
21
+ } ]
22
+ } ]
23
+ },
24
+ "references" : {
25
+ "reference_data" : [ {
26
+ "url" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
27
+ "name" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
28
+ "refsource" : "MISC",
29
+ "tags" : [ "Vendor Advisory" ]
30
+ } ]
31
+ },
32
+ "description" : {
33
+ "description_data" : [ {
34
+ "lang" : "en",
35
+ "value" : "Bitcoin SV before 0.1.1 allows uncontrolled resource consumption when receiving messages with invalid checksums."
36
+ } ]
37
+ }
38
+ },
39
+ "configurations" : {
40
+ "CVE_data_version" : "4.0",
41
+ "nodes" : [ {
42
+ "operator" : "OR",
43
+ "cpe_match" : [ {
44
+ "vulnerable" : true,
45
+ "cpe23Uri" : "cpe:2.3:a:bitcoinsv:bitcoin_sv:*:*:*:*:*:*:*:*",
46
+ "versionEndExcluding" : "0.1.1"
47
+ } ]
48
+ } ]
49
+ },
50
+ "impact" : {
51
+ "baseMetricV3" : {
52
+ "cvssV3" : {
53
+ "version" : "3.1",
54
+ "vectorString" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
55
+ "attackVector" : "NETWORK",
56
+ "attackComplexity" : "LOW",
57
+ "privilegesRequired" : "NONE",
58
+ "userInteraction" : "NONE",
59
+ "scope" : "UNCHANGED",
60
+ "confidentialityImpact" : "NONE",
61
+ "integrityImpact" : "NONE",
62
+ "availabilityImpact" : "HIGH",
63
+ "baseScore" : 7.5,
64
+ "baseSeverity" : "HIGH"
65
+ },
66
+ "exploitabilityScore" : 3.9,
67
+ "impactScore" : 3.6
68
+ },
69
+ "baseMetricV2" : {
70
+ "cvssV2" : {
71
+ "version" : "2.0",
72
+ "vectorString" : "AV:N/AC:L/Au:N/C:N/I:N/A:P",
73
+ "accessVector" : "NETWORK",
74
+ "accessComplexity" : "LOW",
75
+ "authentication" : "NONE",
76
+ "confidentialityImpact" : "NONE",
77
+ "integrityImpact" : "NONE",
78
+ "availabilityImpact" : "PARTIAL",
79
+ "baseScore" : 5.0
80
+ },
81
+ "severity" : "MEDIUM",
82
+ "exploitabilityScore" : 10.0,
83
+ "impactScore" : 2.9,
84
+ "acInsufInfo" : false,
85
+ "obtainAllPrivilege" : false,
86
+ "obtainUserPrivilege" : false,
87
+ "obtainOtherPrivilege" : false,
88
+ "userInteractionRequired" : false
89
+ }
90
+ },
91
+ "publishedDate" : "2020-12-23T17:15Z",
92
+ "lastModifiedDate" : "2020-12-23T20:10Z"
93
+ }, {
94
+ "cve" : {
95
+ "data_type" : "CVE",
96
+ "data_format" : "MITRE",
97
+ "data_version" : "4.0",
98
+ "CVE_data_meta" : {
99
+ "ID" : "CVE-2018-1000892",
100
+ "ASSIGNER" : "cve@mitre.org"
101
+ },
102
+ "problemtype" : {
103
+ "problemtype_data" : [ {
104
+ "description" : [ {
105
+ "lang" : "en",
106
+ "value" : "CWE-400"
107
+ } ]
108
+ } ]
109
+ },
110
+ "references" : {
111
+ "reference_data" : [ {
112
+ "url" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
113
+ "name" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
114
+ "refsource" : "MISC",
115
+ "tags" : [ "Vendor Advisory" ]
116
+ } ]
117
+ },
118
+ "description" : {
119
+ "description_data" : [ {
120
+ "lang" : "en",
121
+ "value" : "Bitcoin SV before 0.1.1 allows uncontrolled resource consumption when receiving sendheaders messages."
122
+ } ]
123
+ }
124
+ },
125
+ "configurations" : {
126
+ "CVE_data_version" : "4.0",
127
+ "nodes" : [ {
128
+ "operator" : "OR",
129
+ "cpe_match" : [ {
130
+ "vulnerable" : true,
131
+ "cpe23Uri" : "cpe:2.3:a:bitcoinsv:bitcoin_sv:*:*:*:*:*:*:*:*",
132
+ "versionEndExcluding" : "0.1.1"
133
+ } ]
134
+ } ]
135
+ },
136
+ "impact" : {
137
+ "baseMetricV3" : {
138
+ "cvssV3" : {
139
+ "version" : "3.1",
140
+ "vectorString" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
141
+ "attackVector" : "NETWORK",
142
+ "attackComplexity" : "LOW",
143
+ "privilegesRequired" : "NONE",
144
+ "userInteraction" : "NONE",
145
+ "scope" : "UNCHANGED",
146
+ "confidentialityImpact" : "NONE",
147
+ "integrityImpact" : "NONE",
148
+ "availabilityImpact" : "HIGH",
149
+ "baseScore" : 7.5,
150
+ "baseSeverity" : "HIGH"
151
+ },
152
+ "exploitabilityScore" : 3.9,
153
+ "impactScore" : 3.6
154
+ },
155
+ "baseMetricV2" : {
156
+ "cvssV2" : {
157
+ "version" : "2.0",
158
+ "vectorString" : "AV:N/AC:L/Au:N/C:N/I:N/A:P",
159
+ "accessVector" : "NETWORK",
160
+ "accessComplexity" : "LOW",
161
+ "authentication" : "NONE",
162
+ "confidentialityImpact" : "NONE",
163
+ "integrityImpact" : "NONE",
164
+ "availabilityImpact" : "PARTIAL",
165
+ "baseScore" : 5.0
166
+ },
167
+ "severity" : "MEDIUM",
168
+ "exploitabilityScore" : 10.0,
169
+ "impactScore" : 2.9,
170
+ "acInsufInfo" : false,
171
+ "obtainAllPrivilege" : false,
172
+ "obtainUserPrivilege" : false,
173
+ "obtainOtherPrivilege" : false,
174
+ "userInteractionRequired" : false
175
+ }
176
+ },
177
+ "publishedDate" : "2020-12-23T17:15Z",
178
+ "lastModifiedDate" : "2020-12-23T20:10Z"
179
+ } ]
180
+ }