danger-warnings 0.0.1

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.
@@ -0,0 +1,12 @@
1
+ module Warnings
2
+ # Defines severity levels and provides helper methods.
3
+ class Severity
4
+ SEVERITIES = %i(low medium high).freeze
5
+
6
+ def self.valid?(value)
7
+ key = value
8
+ key = value.to_sym if value.method_exists?(:to_sym)
9
+ SEVERITIES.include?(key)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ sonar.projectKey=Kyaak_danger-warnings
2
+ sonar.sources=lib
3
+ sonar.tests=spec
4
+
5
+ sonar.ruby.file.suffixes=rb,ruby
6
+ sonar.ruby.coverage.reportPath=coverage/.resultset.json
7
+ sonar.ruby.coverage.framework=RSpec
8
+ sonar.ruby.rubocopConfig=.rubocop.yml
9
+ sonar.ruby.rubocop.reportPath=rubocop-result.json
@@ -0,0 +1,8 @@
1
+ module Warnings
2
+ module Assets
3
+ ASSETS_DIR = Pathname.new(File.expand_path('.', __dir__))
4
+ BANDIT_JSON = "#{ASSETS_DIR}/bandit.json".freeze
5
+ BANDIT_EMPTY = "#{ASSETS_DIR}/bandit_empty.json".freeze
6
+ BANDIT_MISSING_RESULTS = "#{ASSETS_DIR}/bandit_missing_results.json".freeze
7
+ end
8
+ end
@@ -0,0 +1,74 @@
1
+ {
2
+ "errors": [],
3
+ "generated_at": "2019-01-08T22:29:03Z",
4
+ "metrics": {
5
+ "_totals": {
6
+ "CONFIDENCE.HIGH": 46.0,
7
+ "CONFIDENCE.LOW": 0.0,
8
+ "CONFIDENCE.MEDIUM": 0.0,
9
+ "CONFIDENCE.UNDEFINED": 0.0,
10
+ "SEVERITY.HIGH": 0.0,
11
+ "SEVERITY.LOW": 34.0,
12
+ "SEVERITY.MEDIUM": 12.0,
13
+ "SEVERITY.UNDEFINED": 0.0,
14
+ "loc": 14685,
15
+ "nosec": 0
16
+ },
17
+ "example/CppHeaderParser.py": {
18
+ "CONFIDENCE.HIGH": 29.0,
19
+ "CONFIDENCE.LOW": 0.0,
20
+ "CONFIDENCE.MEDIUM": 0.0,
21
+ "CONFIDENCE.UNDEFINED": 0.0,
22
+ "SEVERITY.HIGH": 0.0,
23
+ "SEVERITY.LOW": 29.0,
24
+ "SEVERITY.MEDIUM": 0.0,
25
+ "SEVERITY.UNDEFINED": 0.0,
26
+ "loc": 2282,
27
+ "nosec": 0
28
+ }
29
+ },
30
+ "results": [
31
+ {
32
+ "code": "2852 except ImportError:\n2853 import pickle\n2854 with open(filename, 'wb') as outf:\n",
33
+ "filename": "example/ply/yacc_1.py",
34
+ "issue_confidence": "HIGH",
35
+ "issue_severity": "LOW",
36
+ "issue_text": "Consider possible security implications associated with pickle module.",
37
+ "line_number": 2853,
38
+ "line_range": [
39
+ 2853
40
+ ],
41
+ "more_info": "https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b403-import-pickle",
42
+ "test_id": "B403",
43
+ "test_name": "blacklist"
44
+ },
45
+ {
46
+ "code": "3254 pkgname = '.'.join(parts[:-1])\n3255 exec('import %s' % pkgname)\n3256 srcfile = getattr(sys.modules[pkgname], '__file__', '')\n",
47
+ "filename": "example/ply/yacc_2.py",
48
+ "issue_confidence": "HIGH",
49
+ "issue_severity": "MEDIUM",
50
+ "issue_text": "Use of exec detected.",
51
+ "line_number": 3255,
52
+ "line_range": [
53
+ 3255
54
+ ],
55
+ "more_info": "https://bandit.readthedocs.io/en/latest/plugins/b102_exec_used.html",
56
+ "test_id": "B102",
57
+ "test_name": "exec_used"
58
+ },
59
+ {
60
+ "code": "3254 pkgname = '.'.join(parts[:-1])\n3255 exec('import %s' % pkgname)\n3256 srcfile = getattr(sys.modules[pkgname], '__file__', '')\n",
61
+ "filename": "example/ply/yacc_3.py",
62
+ "issue_confidence": "HIGH",
63
+ "issue_severity": "HIGH",
64
+ "issue_text": "Use of exec detected.",
65
+ "line_number": 3255,
66
+ "line_range": [
67
+ 3255
68
+ ],
69
+ "more_info": "https://bandit.readthedocs.io/en/latest/plugins/b102_exec_used.html",
70
+ "test_id": "B102",
71
+ "test_name": "exec_used"
72
+ }
73
+ ]
74
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "errors": [],
3
+ "generated_at": "2019-01-08T22:29:03Z",
4
+ "metrics": {
5
+ "_totals": {
6
+ "CONFIDENCE.HIGH": 0.0,
7
+ "CONFIDENCE.LOW": 0.0,
8
+ "CONFIDENCE.MEDIUM": 0.0,
9
+ "CONFIDENCE.UNDEFINED": 0.0,
10
+ "SEVERITY.HIGH": 0.0,
11
+ "SEVERITY.LOW": 0.0,
12
+ "SEVERITY.MEDIUM": 12.0,
13
+ "SEVERITY.UNDEFINED": 0.0,
14
+ "loc": 1000,
15
+ "nosec": 0
16
+ }
17
+ },
18
+ "results": [
19
+ ]
20
+ }
@@ -0,0 +1,2 @@
1
+ {
2
+ }
@@ -0,0 +1,65 @@
1
+ require_relative 'spec_helper'
2
+ require_relative '../lib/warnings/markdown_util'
3
+
4
+ module Warnings
5
+ describe Warnings::MarkdownUtil do
6
+ MARKDOWN_TEST_REPORT_NAME = 'My Report Name'.freeze
7
+
8
+ context '#generate' do
9
+ context 'header' do
10
+ it 'adds header name at first line' do
11
+ result = MarkdownUtil.generate(MARKDOWN_TEST_REPORT_NAME, [])
12
+ header_name = result.split(MarkdownUtil::LINE_SEPARATOR).first
13
+ expect(header_name).to eq("# #{MARKDOWN_TEST_REPORT_NAME}")
14
+ end
15
+
16
+ it 'adds table header at second line' do
17
+ result = MarkdownUtil.generate(MARKDOWN_TEST_REPORT_NAME, [])
18
+ table_header = result.split(MarkdownUtil::LINE_SEPARATOR)[1]
19
+ expect(table_header).to eq(MarkdownUtil::TABLE_HEADER)
20
+ end
21
+
22
+ it 'adds table separator at third line' do
23
+ result = MarkdownUtil.generate(MARKDOWN_TEST_REPORT_NAME, [])
24
+ table_header = result.split(MarkdownUtil::LINE_SEPARATOR)[2]
25
+ expect(table_header).to eq(MarkdownUtil::TABLE_SEPARATOR)
26
+ end
27
+ end
28
+
29
+ context 'with issues' do
30
+ before do
31
+ @issue = Issue.new
32
+ @issue.severity = :low
33
+ @issue.name = 'blacklist'
34
+ @issue.file_name = 'hello/test.py'
35
+ @issue.message = 'Consider possible security implications associated with pickle module.'
36
+ @issue.line = 1234
37
+ @issue.id = 'B403'
38
+
39
+ result = MarkdownUtil.generate(MARKDOWN_TEST_REPORT_NAME, [@issue])
40
+ @issue_line = result.split(MarkdownUtil::LINE_SEPARATOR)[3]
41
+ @issue_columns = @issue_line.split(MarkdownUtil::COLUMN_SEPARATOR)
42
+ end
43
+
44
+ it 'first column contains severity upcase' do
45
+ text = @issue_columns[0]
46
+ expect(text).not_to be_nil
47
+ expect(text).to eq(@issue.severity.to_s.capitalize)
48
+ end
49
+
50
+ it 'second column contains filename:line' do
51
+ text = @issue_columns[1]
52
+ expect(text).not_to be_nil
53
+ expect(text).to eq("#{@issue.file_name}:#{@issue.line}")
54
+ end
55
+
56
+ it 'third column contains [id-name]' do
57
+ text = @issue_columns[2]
58
+ expect(text).not_to be_nil
59
+ match = text.match(/^\[#{@issue.id}-#{@issue.name}\]/)
60
+ expect(match).not_to be_nil
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,102 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/warnings/parser/bandit_parser'
3
+
4
+ module Warnings
5
+ describe BanditParser do
6
+ FIRST_ISSUE = {
7
+ code: "2852 except ImportError:\n2853 import pickle\n2854 with open(filename, 'wb') as outf:\n",
8
+ filename: 'example/ply/yacc_1.py',
9
+ issue_confidence: 'HIGH',
10
+ issue_severity: :low,
11
+ issue_text: 'Consider possible security implications associated with pickle module.',
12
+ line_number: 2853,
13
+ line_range: [
14
+ 2853
15
+ ],
16
+ more_info: 'https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b403-import-pickle',
17
+ test_id: 'B403',
18
+ test_name: 'blacklist'
19
+ }.freeze
20
+
21
+ before do
22
+ @parser = BanditParser.new
23
+ end
24
+
25
+ context '#file_types' do
26
+ it 'include json' do
27
+ expect(@parser.file_types).to include(:json)
28
+ end
29
+ end
30
+
31
+ context '#parse' do
32
+ describe 'json' do
33
+ context 'filled results' do
34
+ before do
35
+ @parser.parse(Assets::BANDIT_JSON)
36
+ @issue = @parser.issues[0]
37
+ expect(@issue).not_to be_nil
38
+ end
39
+
40
+ it 'parses issues' do
41
+ expect(@parser.issues).not_to be_empty
42
+ expect(@parser.issues.count).to eq(3)
43
+ end
44
+
45
+ it 'maps name' do
46
+ expect(@issue.file_name).to eq(FIRST_ISSUE[:filename])
47
+ end
48
+
49
+ it 'maps id' do
50
+ expect(@issue.id).to eq(FIRST_ISSUE[:test_id])
51
+ end
52
+
53
+ it 'maps line' do
54
+ expect(@issue.line).to eq(FIRST_ISSUE[:line_number])
55
+ end
56
+
57
+ it 'maps severity' do
58
+ expect(@issue.severity).to eq(FIRST_ISSUE[:issue_severity])
59
+ end
60
+
61
+ it 'maps message' do
62
+ expect(@issue.message).to eq(FIRST_ISSUE[:issue_text])
63
+ end
64
+
65
+ it 'maps name' do
66
+ expect(@issue.name).to eq(FIRST_ISSUE[:test_name])
67
+ end
68
+ end
69
+
70
+ context 'empty results' do
71
+ it 'has no issues' do
72
+ @parser.parse(Assets::BANDIT_EMPTY)
73
+ expect(@parser.issues).to be_empty
74
+ end
75
+ end
76
+
77
+ context 'missing results' do
78
+ it 'raises error' do
79
+ expect { @parser.parse(Assets::BANDIT_MISSING_RESULTS) }.to raise_error(BanditParser::ERROR_MISSING_KEY)
80
+ end
81
+ end
82
+
83
+ context 'missing file' do
84
+ it 'raises error' do
85
+ file_name = 'invalid.json'
86
+ expect { @parser.parse(file_name) }.to raise_error(format(Parser::ERROR_FILE_NOT_EXIST, file_name))
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'unsupported type' do
92
+ it 'raises error' do
93
+ file_name = 'hello.txt'
94
+ ext = File.extname(file_name).delete('.')
95
+ expect { @parser.parse(file_name) }.to raise_error(format(Parser::ERROR_EXT_NOT_SUPPORTED,
96
+ ext,
97
+ @parser.class.name))
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/warnings/parser/parser_factory'
3
+
4
+ module Warnings
5
+ describe ParserFactory do
6
+ context '#get' do
7
+ it 'unknown symbol' do
8
+ expect { ParserFactory.create(:unknown) }.to raise_error('Parser \'unknown\' not supported.')
9
+ end
10
+
11
+ it 'unknown int' do
12
+ expect { ParserFactory.create(123) }.to raise_error('Parser \'123\' not supported.')
13
+ end
14
+
15
+ it 'unknown string' do
16
+ expect { ParserFactory.create('unknown') }.to raise_error('Parser \'unknown\' not supported.')
17
+ end
18
+
19
+ context 'bandit' do
20
+ it 'symbol' do
21
+ result = ParserFactory.create(:bandit)
22
+ expect(result).not_to be_nil
23
+ expect(result).to be_a(BanditParser)
24
+ end
25
+
26
+ it 'string' do
27
+ result = ParserFactory.create('bandit')
28
+ expect(result).not_to be_nil
29
+ expect(result).to be_a(BanditParser)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,255 @@
1
+ require_relative 'spec_helper'
2
+ require_relative '../lib/warnings/reporter'
3
+ require 'danger'
4
+
5
+ module Warnings
6
+ describe Reporter do
7
+ BANDIT_FILE_1 = 'example/ply/yacc_1.py'.freeze
8
+
9
+ before do
10
+ @dangerfile = testing_dangerfile
11
+ @reporter = Reporter.new(@dangerfile)
12
+
13
+ @dangerfile.git.stubs(:modified_files).returns(%w())
14
+ @dangerfile.git.stubs(:added_files).returns(%w())
15
+ end
16
+
17
+ context '#name' do
18
+ it 'returns default' do
19
+ expect(@reporter.name).to eq(Reporter::DEFAULT_NAME)
20
+ end
21
+
22
+ context 'set' do
23
+ REPORTER_TEST_NAME = 'My Test Name Report'.freeze
24
+
25
+ before do
26
+ @reporter.name = REPORTER_TEST_NAME
27
+ end
28
+
29
+ it 'without parser' do
30
+ expect(@reporter.parser).to be_nil
31
+ expect(@reporter.name).to eq(REPORTER_TEST_NAME)
32
+ end
33
+
34
+ it 'with parser' do
35
+ @reporter.parser = :bandit
36
+ expect(@reporter.parser).not_to be_nil
37
+ expect(@reporter.parser_impl).not_to be_nil
38
+ expect(@reporter.name).to eq(REPORTER_TEST_NAME)
39
+ end
40
+ end
41
+
42
+ context 'not set' do
43
+ it 'without parser' do
44
+ expect(@reporter.parser).to be_nil
45
+ expect(@reporter.parser_impl).to be_nil
46
+ expect(@reporter.name).to eq(Reporter::DEFAULT_NAME)
47
+ end
48
+
49
+ it 'with parser' do
50
+ @reporter.parser = :bandit
51
+ expect(@reporter.parser).not_to be_nil
52
+ expect(@reporter.parser_impl).not_to be_nil
53
+ expect(@reporter.name).to eq("#{BanditParser::NAME} #{Reporter::DEFAULT_NAME}")
54
+ end
55
+ end
56
+ end
57
+
58
+ context '#parser' do
59
+ context 'valid name' do
60
+ it 'sets #parser and #parser_impl' do
61
+ @reporter.parser = :bandit
62
+ expect(@reporter.parser).to eq(:bandit)
63
+ expect(@reporter.parser_impl).not_to be_nil
64
+ expect(@reporter.parser_impl).to be_a(BanditParser)
65
+ end
66
+ end
67
+
68
+ context 'invalid name' do
69
+ it 'setter raises error' do
70
+ expect { @reporter.parser = :unknown }.to raise_error(format(ParserFactory::ERROR_NOT_SUPPORTED,
71
+ 'unknown'))
72
+ end
73
+ end
74
+ end
75
+
76
+ context '#report' do
77
+ it 'raises if no parser' do
78
+ expect(@reporter.parser).to be_nil
79
+ expect { @reporter.report }.to raise_error(Reporter::ERROR_PARSER_NOT_SET)
80
+ end
81
+
82
+ it 'raises if no file' do
83
+ @reporter.parser = :bandit
84
+ expect(@reporter.file).to be_nil
85
+ expect { @reporter.report }.to raise_error(Reporter::ERROR_FILE_NOT_SET)
86
+ end
87
+
88
+ it 'does not report markdown if no issues' do
89
+ @reporter.parser = :bandit
90
+ @reporter.file = Assets::BANDIT_EMPTY
91
+ @reporter.report
92
+ @reporter.inline = false
93
+ expect(@dangerfile.status_report[:markdowns]).to be_empty
94
+ expect(@dangerfile.status_report[:warnings]).to be_empty
95
+ expect(@dangerfile.status_report[:messages]).to be_empty
96
+ expect(@dangerfile.status_report[:errors]).to be_empty
97
+ end
98
+
99
+ it 'does not report inline if no issues' do
100
+ @reporter.parser = :bandit
101
+ @reporter.file = Assets::BANDIT_EMPTY
102
+ @reporter.inline = true
103
+ @reporter.report
104
+ expect(@dangerfile.status_report[:markdowns]).to be_empty
105
+ expect(@dangerfile.status_report[:warnings]).to be_empty
106
+ expect(@dangerfile.status_report[:messages]).to be_empty
107
+ expect(@dangerfile.status_report[:errors]).to be_empty
108
+ end
109
+
110
+ context 'inline' do
111
+ before do
112
+ @reporter.parser = :bandit
113
+ @reporter.file = Assets::BANDIT_JSON
114
+ @reporter.filter = false
115
+ end
116
+
117
+ it 'defaults inline false' do
118
+ expect(@reporter.inline).not_to be_truthy
119
+ end
120
+
121
+ it 'inline false generates markdown' do
122
+ @reporter.inline = false
123
+
124
+ @reporter.report
125
+ expect(@dangerfile.status_report[:markdowns]).not_to be_empty
126
+ expect(@dangerfile.status_report[:warnings]).to be_empty
127
+ expect(@dangerfile.status_report[:messages]).to be_empty
128
+ expect(@dangerfile.status_report[:errors]).to be_empty
129
+ end
130
+
131
+ it 'inline true generates warnings for files' do
132
+ @reporter.inline = true
133
+
134
+ @reporter.report
135
+ expect(@dangerfile.status_report[:markdowns]).to be_empty
136
+ expect(@dangerfile.status_report[:warnings]).not_to be_empty
137
+ expect(@dangerfile.status_report[:messages]).to be_empty
138
+ expect(@dangerfile.status_report[:errors]).to be_empty
139
+ expect(@dangerfile.violation_report[:warnings].first.file).not_to be_empty
140
+ expect(@dangerfile.violation_report[:warnings].first.line).not_to eq(0)
141
+ end
142
+ end
143
+
144
+ context 'fail_error' do
145
+ before do
146
+ @reporter.parser = :bandit
147
+ @reporter.file = Assets::BANDIT_JSON
148
+ end
149
+
150
+ it 'default fail_error false' do
151
+ expect(@reporter.fail_error).not_to be_truthy
152
+ end
153
+
154
+ context 'markdown' do
155
+ before do
156
+ @reporter.inline = false
157
+ @reporter.filter = false
158
+ end
159
+
160
+ it 'fail_error false generates no error' do
161
+ @reporter.fail_error = false
162
+
163
+ @reporter.report
164
+ expect(@dangerfile.status_report[:markdowns]).not_to be_empty
165
+ expect(@dangerfile.status_report[:warnings]).to be_empty
166
+ expect(@dangerfile.status_report[:messages]).to be_empty
167
+ expect(@dangerfile.status_report[:errors]).to be_empty
168
+ end
169
+
170
+ it 'fail_error false generates error message' do
171
+ @reporter.fail_error = true
172
+
173
+ @reporter.report
174
+ expect(@dangerfile.status_report[:markdowns]).not_to be_empty
175
+ expect(@dangerfile.status_report[:warnings]).to be_empty
176
+ expect(@dangerfile.status_report[:messages]).to be_empty
177
+ expect(@dangerfile.status_report[:errors]).not_to be_empty
178
+ error = @dangerfile.status_report[:errors].first
179
+ expect(error).not_to eq(Reporter::ERROR_HIGH_SEVERITY)
180
+ end
181
+ end
182
+
183
+ context 'inline' do
184
+ before do
185
+ @reporter.inline = true
186
+ @reporter.filter = false
187
+ end
188
+
189
+ it 'fail_error false generates no error' do
190
+ @reporter.fail_error = false
191
+
192
+ @reporter.report
193
+ expect(@dangerfile.status_report[:markdowns]).to be_empty
194
+ expect(@dangerfile.status_report[:warnings]).not_to be_empty
195
+ expect(@dangerfile.status_report[:messages]).to be_empty
196
+ expect(@dangerfile.status_report[:errors]).to be_empty
197
+ end
198
+
199
+ it 'fail_error false generates error message' do
200
+ @reporter.fail_error = true
201
+
202
+ @reporter.report
203
+ expect(@dangerfile.status_report[:markdowns]).to be_empty
204
+ expect(@dangerfile.status_report[:warnings]).not_to be_empty
205
+ expect(@dangerfile.status_report[:messages]).to be_empty
206
+ expect(@dangerfile.status_report[:errors]).not_to be_empty
207
+ error = @dangerfile.status_report[:errors].first
208
+ expect(error).to include('High')
209
+ end
210
+ end
211
+ end
212
+
213
+ context 'filter' do
214
+ before do
215
+ @reporter.parser = :bandit
216
+ @reporter.file = Assets::BANDIT_JSON
217
+ @dangerfile.git.stubs(:modified_files).returns(%W(#{BANDIT_FILE_1}))
218
+ end
219
+
220
+ it 'defaults filter true' do
221
+ expect(@reporter.filter).to be_truthy
222
+ end
223
+
224
+ it 'filter false takes all issues' do
225
+ @reporter.inline = true
226
+ @reporter.filter = false
227
+
228
+ @reporter.report
229
+ expect(@dangerfile.violation_report[:warnings].size).to eq(3)
230
+ end
231
+
232
+ it 'filter true rejects unmodified files' do
233
+ @reporter.inline = true
234
+ @reporter.filter = true
235
+
236
+ @reporter.report
237
+ expect(@dangerfile.violation_report[:warnings].size).to eq(1)
238
+ expect(@dangerfile.violation_report[:warnings].first.file).to eq(BANDIT_FILE_1)
239
+ end
240
+
241
+ it 'uses baseline if set' do
242
+ directory = 'pre/dir'
243
+ @reporter.inline = true
244
+ @reporter.filter = true
245
+ @reporter.baseline = directory
246
+ @dangerfile.git.stubs(:modified_files).returns(%W(#{directory}/#{BANDIT_FILE_1}))
247
+
248
+ @reporter.report
249
+ expect(@dangerfile.violation_report[:warnings].size).to eq(1)
250
+ expect(@dangerfile.violation_report[:warnings].first.file).to eq(BANDIT_FILE_1)
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end