sastbox_sdk 1.0.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/README.md +0 -0
- data/lib/sastbox-sdk.rb +26 -0
- data/lib/sastbox-sdk/codebase.rb +9 -0
- data/lib/sastbox-sdk/cwe_constants.rb +87 -0
- data/lib/sastbox-sdk/cwe_detector.rb +202 -0
- data/lib/sastbox-sdk/opt_parser.rb +45 -0
- data/lib/sastbox-sdk/printer.rb +86 -0
- data/lib/sastbox-sdk/reporter_sarif.rb +112 -0
- data/lib/sastbox-sdk/runner.rb +55 -0
- data/lib/sastbox-sdk/scanner.rb +152 -0
- data/lib/sastbox-sdk/severity_calculator.rb +82 -0
- data/lib/sastbox-sdk/snippet.rb +107 -0
- data/spec/samples/low.php +21 -0
- data/spec/samples/sarif-2.1.0-rtm.5.json +3370 -0
- data/spec/sastbox-sdk/codebase_spec.rb +7 -0
- data/spec/sastbox-sdk/cwe_constants_spec.rb +7 -0
- data/spec/sastbox-sdk/cwe_detector_spec.rb +216 -0
- data/spec/sastbox-sdk/opt_parser_spec.rb +47 -0
- data/spec/sastbox-sdk/printer_spec.rb +59 -0
- data/spec/sastbox-sdk/reporter_sarif_spec.rb +57 -0
- data/spec/sastbox-sdk/runner_spec.rb +92 -0
- data/spec/sastbox-sdk/scanner_spec.rb +238 -0
- data/spec/sastbox-sdk/severity_calculator_spec.rb +126 -0
- data/spec/sastbox-sdk/snippet_spec.rb +175 -0
- data/spec/sastbox-sdk_spec.rb +8 -0
- data/spec/spec_helper.rb +109 -0
- metadata +96 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/sastbox-sdk'
|
3
|
+
|
4
|
+
RSpec.describe 'Scanner' do
|
5
|
+
let(:scanner) do
|
6
|
+
SastBox::Scanner.new(
|
7
|
+
name: 'test_name',
|
8
|
+
name_alias: 'test_alias',
|
9
|
+
description: 'test_desc',
|
10
|
+
support: ['test_support'],
|
11
|
+
version: '0.1',
|
12
|
+
tool: 'test_tool'
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'start_scan' do
|
17
|
+
context 'should raise name error for run method when correct options are provided' do
|
18
|
+
before do
|
19
|
+
scanner.parse_opts(['-o', 'xxx', '-c', 'aaa'])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise name error for run method when correct options are provided" do
|
23
|
+
expect { scanner.start_scan }.to raise_error(NameError) do |error| # #<NameError: undefined local variable or method `run' ...
|
24
|
+
expect( error.message ).to match(/undefined.*run/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'finish_scan' do
|
31
|
+
context 'should exit with status 1' do
|
32
|
+
let(:filename) do
|
33
|
+
File.absolute_path(File.join(File.dirname(__FILE__), '..', 'samples/low.php'))
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:snippet) do
|
37
|
+
scanner.snippet_read(filename, 10)
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:issue) do
|
41
|
+
{
|
42
|
+
title: 'vuln_name',
|
43
|
+
description: 'vuln_description',
|
44
|
+
references: [],
|
45
|
+
filename: filename,
|
46
|
+
snippet: snippet
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
before do
|
51
|
+
scanner.parse_opts(['-o', 'xxx', '-c', 'aaa'])
|
52
|
+
scanner.add_issue(issue)
|
53
|
+
end
|
54
|
+
|
55
|
+
it do
|
56
|
+
expect { scanner.finish_scan }.to raise_error(SystemExit) do |error|
|
57
|
+
expect( error.status ).to eq(1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'should exit with status 0' do
|
63
|
+
let(:filename) do
|
64
|
+
File.absolute_path(File.join(File.dirname(__FILE__), '..', 'samples/low.php'))
|
65
|
+
end
|
66
|
+
|
67
|
+
let(:snippet) do
|
68
|
+
scanner.snippet_read(filename, 10)
|
69
|
+
end
|
70
|
+
|
71
|
+
before do
|
72
|
+
scanner.parse_opts(['-o', 'xxx', '-c', 'aaa'])
|
73
|
+
end
|
74
|
+
|
75
|
+
it do
|
76
|
+
expect { scanner.finish_scan }.to raise_error(SystemExit) do |error|
|
77
|
+
expect( error.status ).to eq(0)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'info' do
|
84
|
+
subject { scanner.info }
|
85
|
+
it 'name' do
|
86
|
+
expect(subject[:name]).to eq 'test_name'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'description' do
|
90
|
+
expect(subject[:description]).to eq 'test_desc'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'support' do
|
94
|
+
expect(subject[:support]).to eq ['test_support']
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'version' do
|
98
|
+
expect(subject[:version]).to eq '0.1'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'add_issue' do
|
103
|
+
context 'when issue should be skipped' do
|
104
|
+
|
105
|
+
let(:snippet) do
|
106
|
+
{evidence_line: {content: 'abc', hash: ''}, evidence_full: {content: 'abc', hash: ''}}
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:issue) do
|
110
|
+
{
|
111
|
+
title: 'vuln_name',
|
112
|
+
description: 'vuln_description',
|
113
|
+
references: [],
|
114
|
+
filename: 'base/.git/xxx',
|
115
|
+
snippet: snippet
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
before do
|
120
|
+
@status = scanner.add_issue(issue)
|
121
|
+
end
|
122
|
+
|
123
|
+
it { expect(@status).to be nil }
|
124
|
+
it { expect(scanner.issues.length).to be 0}
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when issue should not be skipped' do
|
128
|
+
|
129
|
+
let(:filename) do
|
130
|
+
File.absolute_path(File.join(File.dirname(__FILE__), '..', 'samples/low.php'))
|
131
|
+
end
|
132
|
+
|
133
|
+
let(:snippet) do
|
134
|
+
scanner.snippet_read(filename, 10)
|
135
|
+
end
|
136
|
+
|
137
|
+
let(:issue) do
|
138
|
+
{
|
139
|
+
title: 'vuln_name',
|
140
|
+
description: 'vuln_description',
|
141
|
+
references: [],
|
142
|
+
filename: filename,
|
143
|
+
snippet: snippet
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
before do
|
148
|
+
scanner.parse_opts(['-c', '/abc/def/ghi'])
|
149
|
+
@status = scanner.add_issue(issue)
|
150
|
+
end
|
151
|
+
|
152
|
+
#it { expect(@status).to be scanner.issues }
|
153
|
+
it { expect(scanner.issues.length).to be 1}
|
154
|
+
it "hash_issue_v1" do
|
155
|
+
expect(scanner.issues.first[:hash_issue]).to eq '220da2ef86cb34b97e4253f5b212b2a720c93d717e7fec8f243d851441774181'
|
156
|
+
end
|
157
|
+
|
158
|
+
it "hash_issue_v2" do
|
159
|
+
expect(scanner.issues.first[:hash_issue_v2]).to eq '55a52215b49450ebf8fdb8db1d50f4be3d204959989834e25ba2be9e2f2d5b00'
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'parse_json_from_str' do
|
166
|
+
context 'should parse json from string' do
|
167
|
+
it "should parse json from string" do
|
168
|
+
expect(scanner.parse_json_from_str('{"abc": "123"}') ).to be_an Hash
|
169
|
+
expect(scanner.parse_json_from_str('{"abc": "123"}') ).to have_key("abc")
|
170
|
+
expect(scanner.parse_json_from_str('{"abc": "123"}')["abc"] ).to eq "123"
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should return nil when json is invalid" do
|
174
|
+
expect(scanner.parse_json_from_str('xxxxx') ).to eq nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe 'parse_json_from_file' do
|
180
|
+
context 'should parse json from file' do
|
181
|
+
let(:filename_valid) { '/tmp/json_input_valid_test.json' }
|
182
|
+
let(:filename_invalid) { '/tmp/json_input_invalid_test.json' }
|
183
|
+
|
184
|
+
before do
|
185
|
+
File.write(filename_valid, '{"abc": "123"}')
|
186
|
+
File.write(filename_invalid, 'xxxxx')
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should parse json from file" do
|
190
|
+
expect(scanner.parse_json_from_file(filename_valid) ).to be_an Hash
|
191
|
+
expect(scanner.parse_json_from_file(filename_valid) ).to have_key("abc")
|
192
|
+
expect(scanner.parse_json_from_file(filename_valid)["abc"] ).to eq "123"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should return nil when json is invalid" do
|
196
|
+
expect(scanner.parse_json_from_file(filename_invalid) ).to eq nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe 'save_results' do
|
202
|
+
context 'should save results to file' do
|
203
|
+
let(:report) { '/tmp/save_results.json' }
|
204
|
+
|
205
|
+
before do
|
206
|
+
File.delete(report) if File.exist?(report)
|
207
|
+
|
208
|
+
allow(scanner).to receive(:generate_sarif_report) { '{}' }
|
209
|
+
|
210
|
+
scanner.parse_opts(['-o', report])
|
211
|
+
scanner.save_scan_output
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should save results to file" do
|
215
|
+
expect(File.exist?(report)).to be true
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe 'gen_random_tmp_filename' do
|
221
|
+
context 'should generate random filename' do
|
222
|
+
|
223
|
+
it "should generate random filename" do
|
224
|
+
expect(scanner.gen_random_tmp_filename('.xxxyyy')).to match /\/tmp\/.*\.xxxyyy/
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe 'gen_random_tmp_filename_json' do
|
230
|
+
context 'should generate random json filename' do
|
231
|
+
|
232
|
+
it "should generate random json filename" do
|
233
|
+
expect(scanner.gen_random_tmp_filename_json).to match /\/tmp\/.*\.json/
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/sastbox-sdk'
|
3
|
+
|
4
|
+
|
5
|
+
RSpec.describe 'SeverityCalculator' do
|
6
|
+
let(:scanner) do
|
7
|
+
SastBox::Scanner.new(
|
8
|
+
name: 'test_name',
|
9
|
+
name_alias: 'test_alias',
|
10
|
+
description: 'test_desc',
|
11
|
+
support: ['test_support'],
|
12
|
+
version: '0.1',
|
13
|
+
tool: 'test_tool'
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'add_severity' do
|
18
|
+
context 'when dont have severity field' do
|
19
|
+
let(:issue) do
|
20
|
+
{
|
21
|
+
title: 'cmd exec',
|
22
|
+
description: 'cmd exec'
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
before do
|
27
|
+
scanner.add_severity(issue)
|
28
|
+
end
|
29
|
+
|
30
|
+
it {expect( issue[:severity]).to eq :critical}
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when have severity field different from accepted levels' do
|
34
|
+
let(:issue) do
|
35
|
+
{
|
36
|
+
title: 'cmd exec',
|
37
|
+
description: 'cmd exec',
|
38
|
+
severity: 'anything'
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
before do
|
43
|
+
scanner.add_severity(issue)
|
44
|
+
end
|
45
|
+
|
46
|
+
it {expect( issue[:severity]).to eq :critical}
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when have valid severity field' do
|
50
|
+
let(:issue) do
|
51
|
+
{
|
52
|
+
title: 'anything',
|
53
|
+
description: 'anything',
|
54
|
+
severity: :info
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
before do
|
59
|
+
scanner.add_severity(issue)
|
60
|
+
end
|
61
|
+
|
62
|
+
it {expect( issue[:severity]).to eq :info}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
describe 'attempt_to_determine_severity' do
|
68
|
+
context 'when critical' do
|
69
|
+
let(:issue) do
|
70
|
+
{
|
71
|
+
title: 'cmd exec',
|
72
|
+
description: 'cmd exec'
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
it {expect( scanner.attempt_to_determine_severity(issue)).to eq :critical}
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when high' do
|
80
|
+
let(:issue) do
|
81
|
+
{
|
82
|
+
title: 'xss',
|
83
|
+
description: 'xss'
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
it {expect( scanner.attempt_to_determine_severity(issue)).to eq :high}
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when medium' do
|
91
|
+
let(:issue) do
|
92
|
+
{
|
93
|
+
title: 'csrf',
|
94
|
+
description: 'csrf'
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
it {expect( scanner.attempt_to_determine_severity(issue)).to eq :medium}
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when low' do
|
102
|
+
let(:issue) do
|
103
|
+
{
|
104
|
+
title: 'logging',
|
105
|
+
description: 'logging'
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
it {expect( scanner.attempt_to_determine_severity(issue)).to eq :low}
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when undefined' do
|
113
|
+
let(:issue) do
|
114
|
+
{
|
115
|
+
title: 'anything',
|
116
|
+
description: 'anything'
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
it {expect( scanner.attempt_to_determine_severity(issue)).to eq :undefined}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
end
|
126
|
+
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/sastbox-sdk'
|
3
|
+
|
4
|
+
|
5
|
+
RSpec.describe 'snippet' do
|
6
|
+
let(:scanner) do
|
7
|
+
SastBox::Scanner.new(
|
8
|
+
name: 'test_name',
|
9
|
+
name_alias: 'test_alias',
|
10
|
+
description: 'test_desc',
|
11
|
+
support: ['test_support'],
|
12
|
+
version: '0.1',
|
13
|
+
tool: 'test_tool'
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:filename) do
|
18
|
+
File.absolute_path(File.join(File.dirname(__FILE__), '..', 'samples/low.php'))
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'filename_relative' do
|
22
|
+
before do
|
23
|
+
scanner.parse_opts(['-c', '/abc/def/ghi'])
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'filename does not starts with codebase' do
|
27
|
+
it {expect( scanner.filename_relative('/xxx/yyy') ).to be nil }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'filename starts with codebase' do
|
31
|
+
it {expect( scanner.filename_relative('/abc/def/ghi/xxx/yyy') ).to eq 'xxx/yyy' }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'snippet_calculate_hashes' do
|
36
|
+
context 'hashes to match correct value' do
|
37
|
+
let(:snippet) do
|
38
|
+
{evidence_line: {content: 'abc', hash: ''}, evidence_full: {content: 'abc', hash: ''}}
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
scanner.snippet_calculate_hashes(snippet)
|
43
|
+
end
|
44
|
+
|
45
|
+
it {expect( snippet[:evidence_line][:hash]).to eq 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' }
|
46
|
+
|
47
|
+
it {expect( snippet[:evidence_full][:hash]).to eq 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'snippet_read' do
|
52
|
+
context 'when file exists and line is within range' do
|
53
|
+
subject {scanner.snippet_read(filename, 10) }
|
54
|
+
|
55
|
+
it 'snippet[:read_success]' do
|
56
|
+
expect(subject[:read_success]).to be true;
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'snippet[:evidence_line][:content]' do
|
60
|
+
expect(subject[:evidence_line][:content]).to eq "\t\t$cmd = shell_exec( 'ping ' . $target );";
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'snippet[:evidence_line][:hash]' do
|
64
|
+
expect(subject[:evidence_line][:hash]).to eq '9882497a714594ae1d4ac2e167cce7de6cdc7dd4cffa5456bffd7b3194c9d042';
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'snippet[:evidence_full][:hash]' do
|
68
|
+
expect(subject[:evidence_full][:hash]).to eq 'c61da3e81b8847eb0b6b34bda42db8177e120b6b1fc8e19e0ed332d6751000f0';
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when file does not exist' do
|
73
|
+
subject {scanner.snippet_read('/tmp/qwuhasgnewhbeqwyegasdf', 10) }
|
74
|
+
|
75
|
+
it 'snippet[:read_success]' do
|
76
|
+
expect(subject[:read_success]).to be false;
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'snippet[:evidence_line][:content]' do
|
80
|
+
expect(subject[:evidence_line][:content]).to eq ''
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'snippet[:evidence_line][:hash]' do
|
84
|
+
expect(subject[:evidence_line][:hash]).to eq '';
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'snippet[:evidence_full][:hash]' do
|
88
|
+
expect(subject[:evidence_full][:hash]).to eq '';
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when file exists and line is out of range' do
|
93
|
+
subject {scanner.snippet_read(filename, 50000) }
|
94
|
+
|
95
|
+
it 'snippet[:read_success]' do
|
96
|
+
expect(subject[:read_success]).to be false;
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'snippet[:evidence_line][:content]' do
|
100
|
+
expect(subject[:evidence_line][:content]).to eq ''
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'snippet[:evidence_line][:hash]' do
|
104
|
+
expect(subject[:evidence_line][:hash]).to eq '';
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'snippet[:evidence_full][:hash]' do
|
108
|
+
expect(subject[:evidence_full][:hash]).to eq '';
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'snippet_read_range' do
|
114
|
+
context 'when file exists and start/end line is within range' do
|
115
|
+
subject {scanner.snippet_read_range(filename, 17, 18) }
|
116
|
+
|
117
|
+
it 'snippet[:read_success]' do
|
118
|
+
expect(subject[:read_success]).to be true;
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'snippet[:evidence_line][:content]' do
|
122
|
+
expect(subject[:evidence_line][:content]).to eq "\t// Feedback for the end user\r\n\t$html .= \"<pre>{$cmd}</pre>\";\r\n";
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'snippet[:evidence_line][:hash]' do
|
126
|
+
expect(subject[:evidence_line][:hash]).to eq '1beb122abba992b58df776523269522a6b0411679e991f62e2fa116db6d960ff';
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'snippet[:evidence_full][:hash]' do
|
130
|
+
expect(subject[:evidence_full][:hash]).to eq '9a4a2ee8ed7a70956e9960036e036770499f48225f20c42bb8d21a2f40771dc6';
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when file does not exist' do
|
135
|
+
subject {scanner.snippet_read_range('/tmp/qwuhasgnewhbeqwyegasdf', 17, 18) }
|
136
|
+
|
137
|
+
it 'snippet[:read_success]' do
|
138
|
+
expect(subject[:read_success]).to be false;
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'snippet[:evidence_line][:content]' do
|
142
|
+
expect(subject[:evidence_line][:content]).to eq ''
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'snippet[:evidence_line][:hash]' do
|
146
|
+
expect(subject[:evidence_line][:hash]).to eq '';
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'snippet[:evidence_full][:hash]' do
|
150
|
+
expect(subject[:evidence_full][:hash]).to eq '';
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when file exists and start/end line is out of range' do
|
155
|
+
subject {scanner.snippet_read_range(filename, 50000, 60000) }
|
156
|
+
|
157
|
+
it 'snippet[:read_success]' do
|
158
|
+
expect(subject[:read_success]).to be false;
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'snippet[:evidence_line][:content]' do
|
162
|
+
expect(subject[:evidence_line][:content]).to eq ''
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'snippet[:evidence_line][:hash]' do
|
166
|
+
expect(subject[:evidence_line][:hash]).to eq '';
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'snippet[:evidence_full][:hash]' do
|
170
|
+
expect(subject[:evidence_full][:hash]).to eq '';
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|