dradis-csv 5.3.0 → 5.4.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 +4 -4
- data/CHANGELOG.md +3 -0
- data/lib/dradis/plugins/csv/gem_version.rb +1 -1
- metadata +2 -22
- data/.github/pull_request_template.md +0 -45
- data/.gitignore +0 -5
- data/CHANGELOG.template +0 -12
- data/CONTRIBUTING.md +0 -3
- data/Gemfile +0 -23
- data/dradis-csv.gemspec +0 -25
- data/spec/features/upload_spec.rb +0 -381
- data/spec/fixtures/files/simple (copy).csv +0 -2
- data/spec/fixtures/files/simple.csv +0 -2
- data/spec/fixtures/files/simple_malformed.csv +0 -2
- data/spec/jobs/dradis/plugins/csv/mapping_import_job_spec.rb +0 -32
- data/spec/lib/dradis/plugins/csv/importer_spec.rb +0 -223
- data/spec/lib/dradis/plugins/csv/mapping_form_spec.rb +0 -139
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f66806e2230745ce4ab608c4930c575d92e35f577c7a86ff9f888327c313cda9
|
|
4
|
+
data.tar.gz: 2510f5a2d96208375f1a339976dc16c03490cdbabb297728095e178c635f2a20
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a6e489369e1d0a13bb3c60a02b02f1352680a0fe85c39448828891aac46b85a18227d97f62bc7486385dba3345bbb3027edf5fec786485bb54f2956ec5c720e
|
|
7
|
+
data.tar.gz: 90f1df72e003a07b155c3f445905332c63b902d49d753b0b167a33ad6158cfdc5a0408e22565ff36f42868a52f290d97aded1336d4354854d074fd294e45e645
|
data/CHANGELOG.md
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dradis-csv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Martin
|
|
@@ -56,12 +56,7 @@ executables: []
|
|
|
56
56
|
extensions: []
|
|
57
57
|
extra_rdoc_files: []
|
|
58
58
|
files:
|
|
59
|
-
- ".github/pull_request_template.md"
|
|
60
|
-
- ".gitignore"
|
|
61
59
|
- CHANGELOG.md
|
|
62
|
-
- CHANGELOG.template
|
|
63
|
-
- CONTRIBUTING.md
|
|
64
|
-
- Gemfile
|
|
65
60
|
- LICENSE
|
|
66
61
|
- README.md
|
|
67
62
|
- Rakefile
|
|
@@ -75,7 +70,6 @@ files:
|
|
|
75
70
|
- app/views/dradis/plugins/csv/upload/new.html.erb
|
|
76
71
|
- config/initializers/inflections.rb
|
|
77
72
|
- config/routes.rb
|
|
78
|
-
- dradis-csv.gemspec
|
|
79
73
|
- lib/dradis-csv.rb
|
|
80
74
|
- lib/dradis/plugins/csv.rb
|
|
81
75
|
- lib/dradis/plugins/csv/engine.rb
|
|
@@ -85,13 +79,6 @@ files:
|
|
|
85
79
|
- lib/dradis/plugins/csv/mapping.rb
|
|
86
80
|
- lib/dradis/plugins/csv/mapping_form.rb
|
|
87
81
|
- lib/dradis/plugins/csv/version.rb
|
|
88
|
-
- spec/features/upload_spec.rb
|
|
89
|
-
- spec/fixtures/files/simple (copy).csv
|
|
90
|
-
- spec/fixtures/files/simple.csv
|
|
91
|
-
- spec/fixtures/files/simple_malformed.csv
|
|
92
|
-
- spec/jobs/dradis/plugins/csv/mapping_import_job_spec.rb
|
|
93
|
-
- spec/lib/dradis/plugins/csv/importer_spec.rb
|
|
94
|
-
- spec/lib/dradis/plugins/csv/mapping_form_spec.rb
|
|
95
82
|
homepage: http://dradis.com
|
|
96
83
|
licenses:
|
|
97
84
|
- GPL-2
|
|
@@ -113,11 +100,4 @@ requirements: []
|
|
|
113
100
|
rubygems_version: 3.6.9
|
|
114
101
|
specification_version: 4
|
|
115
102
|
summary: CSV add-on for the Dradis Framework.
|
|
116
|
-
test_files:
|
|
117
|
-
- spec/features/upload_spec.rb
|
|
118
|
-
- spec/fixtures/files/simple (copy).csv
|
|
119
|
-
- spec/fixtures/files/simple.csv
|
|
120
|
-
- spec/fixtures/files/simple_malformed.csv
|
|
121
|
-
- spec/jobs/dradis/plugins/csv/mapping_import_job_spec.rb
|
|
122
|
-
- spec/lib/dradis/plugins/csv/importer_spec.rb
|
|
123
|
-
- spec/lib/dradis/plugins/csv/mapping_form_spec.rb
|
|
103
|
+
test_files: []
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
Please review [CONTRIBUTING.md](https://github.com/dradis/dradis-ce/blob/develop/CONTRIBUTING.md) and remove this line.
|
|
2
|
-
|
|
3
|
-
### Summary
|
|
4
|
-
|
|
5
|
-
Provide a general description of the code changes in your pull
|
|
6
|
-
request... were there any bugs you had fixed? If so, mention them. If
|
|
7
|
-
these bugs have open GitHub issues, be sure to tag them here as well,
|
|
8
|
-
to keep the conversation linked together.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
### Testing Steps
|
|
12
|
-
|
|
13
|
-
Provide steps to test functionality, described in detail for someone not familiar with this part of the application / code base
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
### Other Information
|
|
17
|
-
|
|
18
|
-
If there's anything else that's important and relevant to your pull
|
|
19
|
-
request, mention that information here. This could include
|
|
20
|
-
benchmarks, or other information.
|
|
21
|
-
|
|
22
|
-
Thanks for contributing to Dradis!
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
### Copyright assignment
|
|
26
|
-
|
|
27
|
-
Collaboration is difficult with commercial closed source but we want
|
|
28
|
-
to keep as much of the OSS ethos as possible available to users
|
|
29
|
-
who want to fix it themselves.
|
|
30
|
-
|
|
31
|
-
In order to unambiguously own and sell Dradis Framework commercial
|
|
32
|
-
products, we must have the copyright associated with the entire
|
|
33
|
-
codebase. Any code you create which is merged must be owned by us.
|
|
34
|
-
That's not us trying to be a jerks, that's just the way it works.
|
|
35
|
-
|
|
36
|
-
You can delete this section, but the following sentence needs to
|
|
37
|
-
remain in the PR's description:
|
|
38
|
-
|
|
39
|
-
> I assign all rights, including copyright, to any future Dradis
|
|
40
|
-
> work by myself to Security Roots.
|
|
41
|
-
|
|
42
|
-
### Check List
|
|
43
|
-
|
|
44
|
-
- [ ] Added a CHANGELOG entry
|
|
45
|
-
- [ ] Added specs
|
data/CHANGELOG.template
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
[v#.#.#] ([month] [YYYY])
|
|
2
|
-
- [future tense verb] [feature]
|
|
3
|
-
- Upgraded gems:
|
|
4
|
-
- [gem]
|
|
5
|
-
- Bugs fixes:
|
|
6
|
-
- [future tense verb] [bug fix]
|
|
7
|
-
- Bug tracker items:
|
|
8
|
-
- [item]
|
|
9
|
-
- Security Fixes:
|
|
10
|
-
- High: (Authenticated|Unauthenticated) (admin|author|contributor) [vulnerability description]
|
|
11
|
-
- Medium: (Authenticated|Unauthenticated) (admin|author|contributor) [vulnerability description]
|
|
12
|
-
- Low: (Authenticated|Unauthenticated) (admin|author|contributor) [vulnerability description]
|
data/CONTRIBUTING.md
DELETED
data/Gemfile
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
source 'https://rubygems.org'
|
|
2
|
-
|
|
3
|
-
# Declare your gem's dependencies in dradispro-duoweb.gemspec.
|
|
4
|
-
# Bundler will treat runtime dependencies like base dependencies, and
|
|
5
|
-
# development dependencies will be added by default to the :development group.
|
|
6
|
-
gemspec
|
|
7
|
-
|
|
8
|
-
# jquery-rails is used by the dummy application
|
|
9
|
-
# gem "jquery-rails"
|
|
10
|
-
|
|
11
|
-
# Declare any dependencies that are still in development here instead of in
|
|
12
|
-
# your gemspec. These might include edge Rails or gems from your path or
|
|
13
|
-
# Git. Remember to move these dependencies to your gemspec before releasing
|
|
14
|
-
# your gem to rubygems.org.
|
|
15
|
-
|
|
16
|
-
# To use debugger
|
|
17
|
-
# gem 'debugger'
|
|
18
|
-
|
|
19
|
-
if Dir.exist?('../dradis-plugins')
|
|
20
|
-
gem 'dradis-plugins', path: '../dradis-plugins'
|
|
21
|
-
else
|
|
22
|
-
gem 'dradis-plugins', github: 'dradis/dradis-plugins'
|
|
23
|
-
end
|
data/dradis-csv.gemspec
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
$:.push File.expand_path('../lib', __FILE__)
|
|
2
|
-
require 'dradis/plugins/csv/version'
|
|
3
|
-
version = Dradis::Plugins::CSV::VERSION::STRING
|
|
4
|
-
|
|
5
|
-
# Describe your gem and declare its dependencies:
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.platform = Gem::Platform::RUBY
|
|
8
|
-
spec.name = 'dradis-csv'
|
|
9
|
-
spec.version = version
|
|
10
|
-
spec.summary = 'CSV add-on for the Dradis Framework.'
|
|
11
|
-
spec.description = 'This add-on allows you to upload and parse CSV output into Dradis.'
|
|
12
|
-
|
|
13
|
-
spec.license = 'GPL-2'
|
|
14
|
-
|
|
15
|
-
spec.authors = ['Daniel Martin']
|
|
16
|
-
spec.homepage = 'http://dradis.com'
|
|
17
|
-
|
|
18
|
-
spec.files = `git ls-files`.split("\n")
|
|
19
|
-
spec.executables = spec.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
20
|
-
spec.test_files = spec.files.grep(%r{^(spec|features)/})
|
|
21
|
-
|
|
22
|
-
spec.add_dependency 'dradis-plugins', '>= 4.0'
|
|
23
|
-
spec.add_development_dependency 'bundler', '~> 2.0'
|
|
24
|
-
spec.add_development_dependency 'rake'
|
|
25
|
-
end
|
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
require 'rails_helper'
|
|
2
|
-
|
|
3
|
-
# To run, execute from Dradis main app folder:
|
|
4
|
-
# bin/rspec [dradis-plugins path]/spec/features/upload_spec.rb
|
|
5
|
-
|
|
6
|
-
describe 'upload feature', js: true do
|
|
7
|
-
before do
|
|
8
|
-
login_to_project_as_user
|
|
9
|
-
visit project_upload_path(@project)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
context 'uploading a CSV file' do
|
|
13
|
-
let(:file_path) { File.expand_path('../fixtures/files/simple.csv', __dir__) }
|
|
14
|
-
before do
|
|
15
|
-
@headers = CSV.open(file_path, &:readline)
|
|
16
|
-
|
|
17
|
-
find('#state + .combobox').click
|
|
18
|
-
find('#state ~ .combobox-menu .combobox-option', text: 'Published').click
|
|
19
|
-
|
|
20
|
-
find('#uploader + .combobox').click
|
|
21
|
-
find('#uploader ~ .combobox-menu .combobox-option', text: 'Dradis::Plugins::CSV').click
|
|
22
|
-
|
|
23
|
-
attach_file 'file', file_path, visible: false, disabled: false
|
|
24
|
-
|
|
25
|
-
expect(page).to have_text('CSV Upload Mapping', wait: 30)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it 'redirects to the mapping page' do
|
|
29
|
-
expect(current_path).to eq(csv.new_project_upload_path(@project))
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'lists the fields in the table' do
|
|
33
|
-
within('tbody') do
|
|
34
|
-
@headers.each do |header|
|
|
35
|
-
expect(page).to have_selector('td', text: header)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
context 'mapping CSV columns' do
|
|
41
|
-
context 'when identifier not selected' do
|
|
42
|
-
it 'shows a validation message on the page' do
|
|
43
|
-
within all('tbody tr')[3] do
|
|
44
|
-
select 'Evidence Field'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
click_button 'Import CSV'
|
|
48
|
-
expect(page).to have_text('An Issue ID must be selected.')
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
context 'when there are evidence type but no node type selected' do
|
|
53
|
-
it 'shows a validation message on the page' do
|
|
54
|
-
within all('tbody tr')[2] do
|
|
55
|
-
select 'Issue ID'
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
within all('tbody tr')[3] do
|
|
59
|
-
select 'Evidence Field'
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
click_button 'Import CSV'
|
|
63
|
-
expect(page).to have_text('A Node Label must be selected to import evidence records.')
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
context 'valid states' do
|
|
68
|
-
it 'imports the issues based on the selected state' do
|
|
69
|
-
select 'Issue ID', from: 'mappings[field_attributes][0][type]'
|
|
70
|
-
select 'Node', from: 'mappings[field_attributes][3][type]'
|
|
71
|
-
select 'Evidence Field', from: 'mappings[field_attributes][4][type]'
|
|
72
|
-
select 'Evidence Field', from: 'mappings[field_attributes][5][type]'
|
|
73
|
-
|
|
74
|
-
perform_enqueued_jobs do
|
|
75
|
-
click_button 'Import CSV'
|
|
76
|
-
|
|
77
|
-
find('#console .log', wait: 30, match: :first)
|
|
78
|
-
|
|
79
|
-
expect(page).to have_text('Worker process completed.')
|
|
80
|
-
|
|
81
|
-
expect(Issue.published.count).to eq(1)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
context 'invalid states' do
|
|
87
|
-
it 'imports the issues as draft' do
|
|
88
|
-
select 'Issue ID', from: 'mappings[field_attributes][0][type]'
|
|
89
|
-
select 'Node', from: 'mappings[field_attributes][3][type]'
|
|
90
|
-
select 'Evidence Field', from: 'mappings[field_attributes][4][type]'
|
|
91
|
-
select 'Evidence Field', from: 'mappings[field_attributes][5][type]'
|
|
92
|
-
|
|
93
|
-
page.execute_script(<<~JS)
|
|
94
|
-
const select = document.querySelector('#state');
|
|
95
|
-
select.value = 'tampered_value';
|
|
96
|
-
JS
|
|
97
|
-
|
|
98
|
-
perform_enqueued_jobs do
|
|
99
|
-
click_button 'Import CSV'
|
|
100
|
-
|
|
101
|
-
find('#console .log', wait: 30, match: :first)
|
|
102
|
-
|
|
103
|
-
expect(page).to have_text('Worker process completed.')
|
|
104
|
-
|
|
105
|
-
expect(Issue.published.count).to eq(0)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
context 'when project does not have RTP' do
|
|
111
|
-
it 'imports all columns as fields' do
|
|
112
|
-
select 'Issue ID', from: 'mappings[field_attributes][0][type]'
|
|
113
|
-
select 'Node', from: 'mappings[field_attributes][3][type]'
|
|
114
|
-
select 'Evidence Field', from: 'mappings[field_attributes][4][type]'
|
|
115
|
-
select 'Evidence Field', from: 'mappings[field_attributes][5][type]'
|
|
116
|
-
|
|
117
|
-
perform_enqueued_jobs do
|
|
118
|
-
click_button 'Import CSV'
|
|
119
|
-
|
|
120
|
-
find('#console .log', wait: 30, match: :first)
|
|
121
|
-
|
|
122
|
-
expect(page).to have_text('Worker process completed.')
|
|
123
|
-
|
|
124
|
-
issue = Issue.last
|
|
125
|
-
expect(issue.fields).to eq({ 'Description' => 'Test CSV', 'Title' => 'SQL Injection', 'VulnerabilityCategory' =>'High', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
126
|
-
|
|
127
|
-
node = issue.affected.first
|
|
128
|
-
expect(node.label).to eq('10.0.0.1')
|
|
129
|
-
|
|
130
|
-
evidence = node.evidence.first
|
|
131
|
-
expect(evidence.fields).to eq({ 'Label' => '10.0.0.1', 'Title' => 'SQL Injection', 'Location' => '10.0.0.1', 'Port' => '443' })
|
|
132
|
-
|
|
133
|
-
expect(Mapping.where(component: 'csv')).to be_empty
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
context 'when project have RTP' do
|
|
139
|
-
before do
|
|
140
|
-
rtp = create(:report_template_properties, evidence_fields: evidence_fields, issue_fields: issue_fields)
|
|
141
|
-
@project.update(report_template_properties: rtp)
|
|
142
|
-
|
|
143
|
-
page.refresh
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
context 'without fields' do
|
|
147
|
-
let (:evidence_fields) { [] }
|
|
148
|
-
let (:issue_fields) { [] }
|
|
149
|
-
|
|
150
|
-
it 'creates records with fields from the headers' do
|
|
151
|
-
select 'Issue ID', from: 'mappings[field_attributes][0][type]'
|
|
152
|
-
select 'Node', from: 'mappings[field_attributes][3][type]'
|
|
153
|
-
select 'Evidence Field', from: 'mappings[field_attributes][4][type]'
|
|
154
|
-
select 'Evidence Field', from: 'mappings[field_attributes][5][type]'
|
|
155
|
-
|
|
156
|
-
perform_enqueued_jobs do
|
|
157
|
-
click_button 'Import CSV'
|
|
158
|
-
|
|
159
|
-
find('#console .log', wait: 30, match: :first)
|
|
160
|
-
|
|
161
|
-
expect(page).to have_text('Worker process completed.')
|
|
162
|
-
|
|
163
|
-
issue = Issue.last
|
|
164
|
-
expect(issue.fields).to eq({ 'Description' => 'Test CSV', 'Title' => 'SQL Injection', 'Vulnerability Category' =>'High', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
165
|
-
|
|
166
|
-
node = issue.affected.first
|
|
167
|
-
expect(node.label).to eq('10.0.0.1')
|
|
168
|
-
|
|
169
|
-
evidence = node.evidence.first
|
|
170
|
-
expect(evidence.fields).to eq({ 'Label' => '10.0.0.1', 'Location' => '10.0.0.1', 'Title' => 'SQL Injection', 'Port' => '443' })
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
context 'with fields' do
|
|
176
|
-
let (:evidence_fields) {
|
|
177
|
-
[
|
|
178
|
-
{ name: 'Location', type: :string, default: true },
|
|
179
|
-
{ name: 'Port', type: :string, default: true}
|
|
180
|
-
]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
let (:issue_fields) {
|
|
184
|
-
[
|
|
185
|
-
{ name: 'Title', type: :string, default: true },
|
|
186
|
-
{ name: 'Description', type: :string, default: true},
|
|
187
|
-
{ name: 'Severity', type: :string, default: true}
|
|
188
|
-
]
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
it 'shows the available fields for the selected type' do
|
|
192
|
-
select 'Issue Field', from: 'mappings[field_attributes][1][type]'
|
|
193
|
-
|
|
194
|
-
issue_fields.each do |field|
|
|
195
|
-
expect(page).to have_selector('option', text: field[:name])
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
select 'Evidence Field', from: 'mappings[field_attributes][4][type]'
|
|
199
|
-
|
|
200
|
-
evidence_fields.each do |field|
|
|
201
|
-
expect(page).to have_selector('option', text: field[:name])
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
it 'can select which columns to import' do
|
|
206
|
-
select 'Issue ID', from: 'mappings[field_attributes][0][type]'
|
|
207
|
-
|
|
208
|
-
select 'Issue Field', from: 'mappings[field_attributes][1][type]'
|
|
209
|
-
select 'Title', from: 'mappings[field_attributes][1][field]'
|
|
210
|
-
|
|
211
|
-
select 'Issue Field', from: 'mappings[field_attributes][2][type]'
|
|
212
|
-
select 'Description', from: 'mappings[field_attributes][2][field]'
|
|
213
|
-
|
|
214
|
-
select 'Node', from: 'mappings[field_attributes][3][type]'
|
|
215
|
-
|
|
216
|
-
select 'Evidence Field', from: 'mappings[field_attributes][4][type]'
|
|
217
|
-
select 'Location', from: 'mappings[field_attributes][4][field]'
|
|
218
|
-
|
|
219
|
-
select 'Evidence Field', from: 'mappings[field_attributes][5][type]'
|
|
220
|
-
select 'Port', from: 'mappings[field_attributes][5][field]'
|
|
221
|
-
|
|
222
|
-
select 'Issue Field', from: 'mappings[field_attributes][6][type]'
|
|
223
|
-
select 'Severity', from: 'mappings[field_attributes][6][field]'
|
|
224
|
-
|
|
225
|
-
perform_enqueued_jobs do
|
|
226
|
-
click_button 'Import CSV'
|
|
227
|
-
|
|
228
|
-
find('#console .log', wait: 30, match: :first)
|
|
229
|
-
|
|
230
|
-
expect(page).to have_text('Worker process completed.')
|
|
231
|
-
|
|
232
|
-
issue = Issue.last
|
|
233
|
-
expect(issue.fields).to eq({ 'Description' => 'Test CSV', 'Title' => 'SQL Injection', 'Severity' => 'High', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
234
|
-
|
|
235
|
-
node = issue.affected.first
|
|
236
|
-
expect(node.label).to eq('10.0.0.1')
|
|
237
|
-
|
|
238
|
-
evidence = node.evidence.first
|
|
239
|
-
expect(evidence.fields).to eq({ 'Label' => '10.0.0.1', 'Location' => '10.0.0.1', 'Title' => 'SQL Injection', 'Port' => '443' })
|
|
240
|
-
|
|
241
|
-
headers = CSV.open(file_path, &:readline)
|
|
242
|
-
issue_source = Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :issue)
|
|
243
|
-
evidence_source = Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :evidence)
|
|
244
|
-
expect(Mapping.where(component: 'csv').pluck(:source)).to match_array([issue_source, evidence_source])
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
context 'when no evidence fields' do
|
|
250
|
-
let (:evidence_fields) { [] }
|
|
251
|
-
let (:issue_fields) { [] }
|
|
252
|
-
|
|
253
|
-
it 'still creates evidence record' do
|
|
254
|
-
within all('tbody tr')[0] do
|
|
255
|
-
select 'Issue ID'
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
within all('tbody tr')[1] do
|
|
259
|
-
select 'Issue Field'
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
within all('tbody tr')[3] do
|
|
263
|
-
select 'Node'
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
within all('tbody tr')[5] do
|
|
267
|
-
select 'Issue Field'
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
perform_enqueued_jobs do
|
|
271
|
-
click_button 'Import CSV'
|
|
272
|
-
|
|
273
|
-
find('#console .log', wait: 30, match: :first)
|
|
274
|
-
|
|
275
|
-
expect(page).to have_text('Worker process completed.')
|
|
276
|
-
|
|
277
|
-
issue = Issue.last
|
|
278
|
-
expect(issue.fields).to include({ 'Title' => 'SQL Injection', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
279
|
-
|
|
280
|
-
node = issue.affected.first
|
|
281
|
-
expect(node.label).to eq('10.0.0.1')
|
|
282
|
-
|
|
283
|
-
evidence = node.evidence.first
|
|
284
|
-
expect(evidence.content).to eq('')
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
context 'uploading a CSV file with a saved mapping' do
|
|
293
|
-
let(:file_path) { File.expand_path('../fixtures/files/simple.csv', __dir__) }
|
|
294
|
-
|
|
295
|
-
before do
|
|
296
|
-
rtp = create(
|
|
297
|
-
:report_template_properties,
|
|
298
|
-
evidence_fields: [{ name: 'Location', type: :string, default: true }],
|
|
299
|
-
issue_fields: [{ name: 'Title', type: :string, default: true }]
|
|
300
|
-
)
|
|
301
|
-
@project.update(report_template_properties: rtp)
|
|
302
|
-
|
|
303
|
-
headers = CSV.open(file_path, &:readline)
|
|
304
|
-
issue_mapping = Mapping.create!(
|
|
305
|
-
component: 'csv',
|
|
306
|
-
source: Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :issue),
|
|
307
|
-
destination: rtp.as_mapping_destination
|
|
308
|
-
)
|
|
309
|
-
issue_mapping.mapping_fields.create!(
|
|
310
|
-
source_field: 'Id', destination_field: 'plugin_id', content: '{{ csv[Id] }}'
|
|
311
|
-
)
|
|
312
|
-
issue_mapping.mapping_fields.create!(
|
|
313
|
-
source_field: 'Title', destination_field: 'Title', content: '{{ csv[Title] }}'
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
evidence_mapping = Mapping.create!(
|
|
317
|
-
component: 'csv',
|
|
318
|
-
source: Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :evidence),
|
|
319
|
-
destination: rtp.as_mapping_destination
|
|
320
|
-
)
|
|
321
|
-
evidence_mapping.mapping_fields.create!(
|
|
322
|
-
source_field: 'Host', destination_field: 'node_label', content: '{{ csv[Host] }}'
|
|
323
|
-
)
|
|
324
|
-
evidence_mapping.mapping_fields.create!(
|
|
325
|
-
source_field: 'Location', destination_field: 'Location', content: '{{ csv[Location] }}'
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
page.refresh
|
|
329
|
-
|
|
330
|
-
find('#uploader + .combobox').click
|
|
331
|
-
find('#uploader ~ .combobox-menu .combobox-option', text: 'Dradis::Plugins::CSV').click
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
it 'imports immediately using the saved mapping, without showing the mapper' do
|
|
335
|
-
attach_file 'file', file_path, visible: false, disabled: false
|
|
336
|
-
|
|
337
|
-
expect(page).to have_text('CSV imported using its saved mapping', wait: 30)
|
|
338
|
-
expect(current_path).to eq(main_app.project_upload_manager_path(@project))
|
|
339
|
-
|
|
340
|
-
issue = Issue.last
|
|
341
|
-
expect(issue.fields).to include('Title' => 'SQL Injection', 'plugin' => 'csv', 'plugin_id' => '1')
|
|
342
|
-
|
|
343
|
-
node = issue.affected.first
|
|
344
|
-
expect(node.label).to eq('10.0.0.1')
|
|
345
|
-
|
|
346
|
-
evidence = node.evidence.first
|
|
347
|
-
expect(evidence.fields).to include('Location' => '10.0.0.1')
|
|
348
|
-
end
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
describe 'CSV file samples' do
|
|
352
|
-
before do
|
|
353
|
-
find('#uploader + .combobox').click
|
|
354
|
-
find('#uploader ~ .combobox-menu .combobox-option', text: 'Dradis::Plugins::CSV').click
|
|
355
|
-
|
|
356
|
-
attach_file 'file', file_path, visible: false, disabled: false
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
context 'uploading a malformed CSV file' do
|
|
360
|
-
let(:file_path) { File.expand_path('../fixtures/files/simple_malformed.csv', __dir__) }
|
|
361
|
-
|
|
362
|
-
it 'redirects to upload manager with error' do
|
|
363
|
-
find('.alert.alert-danger', wait: 30)
|
|
364
|
-
|
|
365
|
-
expect(page).to have_text('The uploaded file is not a valid CSV file')
|
|
366
|
-
expect(current_path).to eq(main_app.project_upload_manager_path(@project))
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
context 'uploading any file other than CSV' do
|
|
371
|
-
let(:file_path) { Rails.root.join('spec/fixtures/files/rails.png') }
|
|
372
|
-
|
|
373
|
-
it 'redirects to upload manager with error' do
|
|
374
|
-
find('.alert.alert-danger', wait: 30)
|
|
375
|
-
|
|
376
|
-
expect(page).to have_text('The uploaded file is not a CSV file.')
|
|
377
|
-
expect(current_path).to eq(main_app.project_upload_manager_path(@project))
|
|
378
|
-
end
|
|
379
|
-
end
|
|
380
|
-
end
|
|
381
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'rails_helper'
|
|
2
|
-
|
|
3
|
-
RSpec.describe Dradis::Plugins::CSV::MappingImportJob do
|
|
4
|
-
let(:file) { File.expand_path('../../../.../../../fixtures/files/simple.csv', __dir__) }
|
|
5
|
-
|
|
6
|
-
let(:perform_job) do
|
|
7
|
-
described_class.new.perform(
|
|
8
|
-
default_user_id: create(:user).id,
|
|
9
|
-
file: file,
|
|
10
|
-
headers: CSV.open(file, &:readline),
|
|
11
|
-
mappings: {},
|
|
12
|
-
project_id: create(:project).id,
|
|
13
|
-
state: 'draft',
|
|
14
|
-
uid: 1
|
|
15
|
-
)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
describe '#perform' do
|
|
19
|
-
it 'calls Importer#import_rows' do
|
|
20
|
-
dbl = double('Importer')
|
|
21
|
-
allow(Dradis::Plugins::CSV::Importer).to receive(:new).and_return(dbl)
|
|
22
|
-
expect(dbl).to receive(:import_rows).and_return(true)
|
|
23
|
-
|
|
24
|
-
perform_job
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'writes a known final line in the log' do
|
|
28
|
-
perform_job
|
|
29
|
-
expect(Log.last.text).to eq 'Worker process completed.'
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
require 'rails_helper'
|
|
2
|
-
|
|
3
|
-
RSpec.describe Dradis::Plugins::CSV::Importer do
|
|
4
|
-
let(:file) { File.expand_path('../../../.../../../fixtures/files/simple.csv', __dir__) }
|
|
5
|
-
let(:headers) { CSV.open(file, &:readline) }
|
|
6
|
-
let(:project) { create(:project) }
|
|
7
|
-
|
|
8
|
-
let(:instance) do
|
|
9
|
-
described_class.new(
|
|
10
|
-
default_user_id: create(:user).id,
|
|
11
|
-
logger: Log.new(uid: 1),
|
|
12
|
-
plugin: Dradis::Plugins::CSV,
|
|
13
|
-
project_id: project.id
|
|
14
|
-
)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
let(:import_rows) do
|
|
18
|
-
instance.import_rows(file: file, headers: headers, mappings: mappings)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
describe '#import_rows' do
|
|
22
|
-
context 'when project has RTP' do
|
|
23
|
-
let(:mappings) do
|
|
24
|
-
{
|
|
25
|
-
'0' => { 'type' => 'identifier' },
|
|
26
|
-
'1' => { 'type' => 'issue', 'field' => 'MyTitle' },
|
|
27
|
-
'3' => { 'type' => 'node', 'field' => '' },
|
|
28
|
-
'4' => { 'type' => 'evidence', 'field' => 'MyLocation' },
|
|
29
|
-
'5' => { 'type' => 'evidence', 'field' => '' }
|
|
30
|
-
}
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
before do
|
|
34
|
-
project.update(report_template_properties: create(:report_template_properties))
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'uses the field as Dradis Field' do
|
|
38
|
-
import_rows
|
|
39
|
-
|
|
40
|
-
issue = Issue.first
|
|
41
|
-
expect(issue.fields).to eq({ 'MyTitle' => 'SQL Injection', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
42
|
-
|
|
43
|
-
node = issue.affected.first
|
|
44
|
-
expect(node.label).to eq('10.0.0.1')
|
|
45
|
-
|
|
46
|
-
evidence = node.evidence.first
|
|
47
|
-
expect(evidence.fields).to eq({ 'Label' => '10.0.0.1', 'Title' => '(No #[Title]# field)', 'MyLocation' => '10.0.0.1' })
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
context 'when project does not have RTP' do
|
|
52
|
-
let(:mappings) do
|
|
53
|
-
{
|
|
54
|
-
'0' => { 'type' => 'identifier' },
|
|
55
|
-
'1' => { 'type' => 'issue', 'field' => 'MyTitle' },
|
|
56
|
-
'3' => { 'type' => 'node', 'field' => '' },
|
|
57
|
-
'4' => { 'type' => 'evidence', 'field' => 'MyLocation' },
|
|
58
|
-
'5' => { 'type' => 'evidence', 'field' => '' },
|
|
59
|
-
'6' => { 'type' => 'issue', 'field' => '' }
|
|
60
|
-
}
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it 'uses the column name as Dradis Field' do
|
|
64
|
-
import_rows
|
|
65
|
-
|
|
66
|
-
issue = Issue.first
|
|
67
|
-
expect(issue.fields).to eq({ 'Title' => 'SQL Injection', 'VulnerabilityCategory' => 'High', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
68
|
-
|
|
69
|
-
node = issue.affected.first
|
|
70
|
-
expect(node.label).to eq('10.0.0.1')
|
|
71
|
-
|
|
72
|
-
evidence = node.evidence.first
|
|
73
|
-
expect(evidence.fields).to eq({ 'Label' => '10.0.0.1', 'Location' => '10.0.0.1', 'Port' => '443', 'Title' => 'SQL Injection' })
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
it 'strips out whitespace from column header' do
|
|
77
|
-
import_rows
|
|
78
|
-
|
|
79
|
-
issue = Issue.first
|
|
80
|
-
expect(issue.fields.keys).to include('VulnerabilityCategory')
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
context 'when mapping does not have a node type' do
|
|
85
|
-
let(:mappings) do
|
|
86
|
-
{
|
|
87
|
-
'0' => { 'type' => 'identifier' },
|
|
88
|
-
'1' => { 'type' => 'issue' },
|
|
89
|
-
'4' => { 'type' => 'evidence' }
|
|
90
|
-
}
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it 'does not create node and evidence' do
|
|
94
|
-
import_rows
|
|
95
|
-
|
|
96
|
-
issue = Issue.last
|
|
97
|
-
expect(issue.affected.length).to eq(0)
|
|
98
|
-
expect(issue.evidence.length).to eq(0)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
context 'when no identifier is passed in' do
|
|
103
|
-
let(:mappings) do
|
|
104
|
-
{
|
|
105
|
-
'1' => { 'type' => 'issue' },
|
|
106
|
-
'4' => { 'type' => 'evidence' }
|
|
107
|
-
}
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
it 'uses filename and row index as csv_id' do
|
|
111
|
-
import_rows
|
|
112
|
-
|
|
113
|
-
issue = Issue.last
|
|
114
|
-
expect(issue.fields).to eq({ 'Title' => 'SQL Injection', 'plugin' => 'csv', 'plugin_id' => 'simple.csv-0' })
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
context 'when no evidence fields' do
|
|
119
|
-
let(:mappings) do
|
|
120
|
-
{
|
|
121
|
-
'0' => { 'type' => 'identifier' },
|
|
122
|
-
'1' => { 'type' => 'issue', 'field' => 'MyTitle' },
|
|
123
|
-
'3' => { 'type' => 'node', 'field' => '' }
|
|
124
|
-
}
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it 'still creates evidence record' do
|
|
128
|
-
import_rows
|
|
129
|
-
|
|
130
|
-
issue = Issue.first
|
|
131
|
-
expect(issue.fields).to eq({ 'Title' => 'SQL Injection', 'plugin' => 'csv', 'plugin_id' => '1' })
|
|
132
|
-
|
|
133
|
-
node = issue.affected.first
|
|
134
|
-
expect(node.label).to eq('10.0.0.1')
|
|
135
|
-
|
|
136
|
-
evidence = node.evidence.first
|
|
137
|
-
expect(evidence.content).to eq('')
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
describe '#import' do
|
|
143
|
-
context 'when the project has no RTP' do
|
|
144
|
-
it 'does not import anything' do
|
|
145
|
-
expect(instance.import(file: file)).to eq(false)
|
|
146
|
-
expect(Issue.count).to eq(0)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
context 'when the project has RTP but no saved mapping' do
|
|
151
|
-
before do
|
|
152
|
-
project.update(report_template_properties: create(:report_template_properties))
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
it 'does not import anything' do
|
|
156
|
-
expect(instance.import(file: file)).to eq(false)
|
|
157
|
-
expect(Issue.count).to eq(0)
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
context 'when a saved mapping exists for these headers' do
|
|
162
|
-
let(:rtp) { create(:report_template_properties) }
|
|
163
|
-
|
|
164
|
-
before do
|
|
165
|
-
project.update(report_template_properties: rtp)
|
|
166
|
-
|
|
167
|
-
issue_mapping = Mapping.create!(
|
|
168
|
-
component: 'csv',
|
|
169
|
-
source: Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :issue),
|
|
170
|
-
destination: rtp.as_mapping_destination
|
|
171
|
-
)
|
|
172
|
-
issue_mapping.mapping_fields.create!(
|
|
173
|
-
source_field: 'Id', destination_field: 'plugin_id', content: '{{ csv[Id] }}'
|
|
174
|
-
)
|
|
175
|
-
issue_mapping.mapping_fields.create!(
|
|
176
|
-
source_field: 'Title', destination_field: 'Title', content: '{{ csv[Title] }}'
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
evidence_mapping = Mapping.create!(
|
|
180
|
-
component: 'csv',
|
|
181
|
-
source: Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :evidence),
|
|
182
|
-
destination: rtp.as_mapping_destination
|
|
183
|
-
)
|
|
184
|
-
evidence_mapping.mapping_fields.create!(
|
|
185
|
-
source_field: 'Host', destination_field: 'node_label', content: '{{ csv[Host] }}'
|
|
186
|
-
)
|
|
187
|
-
evidence_mapping.mapping_fields.create!(
|
|
188
|
-
source_field: 'Location', destination_field: 'Location', content: '{{ csv[Location] }}'
|
|
189
|
-
)
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
it 'imports using the saved mapping' do
|
|
193
|
-
expect(instance.import(file: file)).to eq(true)
|
|
194
|
-
|
|
195
|
-
issue = Issue.last
|
|
196
|
-
expect(issue.fields).to include('Title' => 'SQL Injection', 'plugin_id' => '1')
|
|
197
|
-
|
|
198
|
-
node = issue.affected.first
|
|
199
|
-
expect(node.label).to eq('10.0.0.1')
|
|
200
|
-
|
|
201
|
-
evidence = node.evidence.first
|
|
202
|
-
expect(evidence.fields).to include('Location' => '10.0.0.1')
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
describe '.templates' do
|
|
208
|
-
let(:rtp) { create(:report_template_properties) }
|
|
209
|
-
let(:issue_source) { Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :issue) }
|
|
210
|
-
let(:evidence_source) { Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :evidence) }
|
|
211
|
-
|
|
212
|
-
before do
|
|
213
|
-
Mapping.create!(component: 'csv', source: issue_source, destination: rtp.as_mapping_destination)
|
|
214
|
-
Mapping.create!(component: 'csv', source: evidence_source, destination: rtp.as_mapping_destination)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
it 'groups the currently known sources by entity' do
|
|
218
|
-
expect(described_class.templates).to eq(
|
|
219
|
-
issue: [issue_source], evidence: [evidence_source]
|
|
220
|
-
)
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
end
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
require 'rails_helper'
|
|
2
|
-
|
|
3
|
-
RSpec.describe Dradis::Plugins::CSV::MappingForm do
|
|
4
|
-
let(:headers) { ['Id', 'Title', 'Host', 'Vulnerability Category'] }
|
|
5
|
-
let(:destination) { 'rtp_1' }
|
|
6
|
-
let(:rtp_fields) { { issue: ['Title'], evidence: ['Rating'] } }
|
|
7
|
-
let(:column_mappings) do
|
|
8
|
-
{
|
|
9
|
-
'0' => { 'type' => 'identifier' },
|
|
10
|
-
'1' => { 'type' => 'issue', 'field' => 'Title' },
|
|
11
|
-
'2' => { 'type' => 'node', 'field' => '' },
|
|
12
|
-
'3' => { 'type' => 'evidence', 'field' => 'Rating' }
|
|
13
|
-
}
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
let(:issue_source) do
|
|
17
|
-
Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :issue)
|
|
18
|
-
end
|
|
19
|
-
let(:evidence_source) do
|
|
20
|
-
Dradis::Plugins::CSV.mapping_source(headers: headers, entity: :evidence)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
subject(:form) do
|
|
24
|
-
described_class.new(destination: destination, headers: headers, rtp_fields: rtp_fields)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
let(:save) { form.save(column_mappings: column_mappings) }
|
|
28
|
-
|
|
29
|
-
describe '#save' do
|
|
30
|
-
it 'creates one mapping per entity with normalized source fields' do
|
|
31
|
-
expect { save }.to change { Mapping.count }.by(2)
|
|
32
|
-
|
|
33
|
-
issue_mapping = Mapping.find_by(
|
|
34
|
-
component: 'csv', source: issue_source, destination: destination
|
|
35
|
-
)
|
|
36
|
-
expect(issue_mapping.mapping_fields.pluck(:destination_field, :source_field, :content)).to match_array([
|
|
37
|
-
['plugin_id', 'Id', '{{ csv[Id] }}'],
|
|
38
|
-
['Title', 'Title', '{{ csv[Title] }}']
|
|
39
|
-
])
|
|
40
|
-
|
|
41
|
-
evidence_mapping = Mapping.find_by(
|
|
42
|
-
component: 'csv', source: evidence_source, destination: destination
|
|
43
|
-
)
|
|
44
|
-
expect(evidence_mapping.mapping_fields.pluck(:destination_field, :source_field, :content)).to match_array([
|
|
45
|
-
['node_label', 'Host', '{{ csv[Host] }}'],
|
|
46
|
-
['Rating', 'VulnerabilityCategory', '{{ csv[VulnerabilityCategory] }}']
|
|
47
|
-
])
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context 'without a destination' do
|
|
51
|
-
let(:destination) { nil }
|
|
52
|
-
|
|
53
|
-
it 'does not create any mappings' do
|
|
54
|
-
expect { save }.not_to change { Mapping.count }
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
context 'when only skipped or blank columns are assigned to an entity' do
|
|
59
|
-
let(:column_mappings) do
|
|
60
|
-
{
|
|
61
|
-
'0' => { 'type' => 'identifier' },
|
|
62
|
-
'1' => { 'type' => 'issue', 'field' => '' },
|
|
63
|
-
'3' => { 'type' => 'skip' }
|
|
64
|
-
}
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'only stores the fields with a destination' do
|
|
68
|
-
expect { save }.to change { Mapping.count }.by(1)
|
|
69
|
-
|
|
70
|
-
issue_mapping = Mapping.find_by(
|
|
71
|
-
component: 'csv', source: issue_source, destination: destination
|
|
72
|
-
)
|
|
73
|
-
expect(issue_mapping.mapping_fields.pluck(:destination_field)).to eq(['plugin_id'])
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
context 'when the RTP has no fields defined for an entity' do
|
|
78
|
-
let(:rtp_fields) { { issue: ['Title'], evidence: [] } }
|
|
79
|
-
|
|
80
|
-
it 'does not create a mapping for that entity, even for its identifier/node column' do
|
|
81
|
-
expect { save }.to change { Mapping.count }.by(1)
|
|
82
|
-
|
|
83
|
-
expect(Mapping.find_by(source: evidence_source)).to be_nil
|
|
84
|
-
|
|
85
|
-
issue_mapping = Mapping.find_by(
|
|
86
|
-
component: 'csv', source: issue_source, destination: destination
|
|
87
|
-
)
|
|
88
|
-
expect(issue_mapping.mapping_fields.pluck(:destination_field)).to match_array(['plugin_id', 'Title'])
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
context 'when the RTP has no fields defined for either entity' do
|
|
93
|
-
let(:rtp_fields) { { issue: [], evidence: [] } }
|
|
94
|
-
|
|
95
|
-
it 'does not create any mappings' do
|
|
96
|
-
expect { save }.not_to change { Mapping.count }
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
context 'when a column is assigned to a custom field' do
|
|
101
|
-
let(:column_mappings) do
|
|
102
|
-
{
|
|
103
|
-
'0' => { 'type' => 'identifier' },
|
|
104
|
-
'1' => { 'type' => 'issue', 'field' => 'Custom Field', 'custom_field' => 'CVSS Score' },
|
|
105
|
-
'2' => { 'type' => 'node', 'field' => '' },
|
|
106
|
-
'3' => { 'type' => 'evidence', 'field' => 'Rating' }
|
|
107
|
-
}
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
it 'stores the typed-in name as the destination field' do
|
|
111
|
-
save
|
|
112
|
-
|
|
113
|
-
issue_mapping = Mapping.find_by(
|
|
114
|
-
component: 'csv', source: issue_source, destination: destination
|
|
115
|
-
)
|
|
116
|
-
expect(issue_mapping.mapping_fields.pluck(:destination_field)).to match_array(['plugin_id', 'CVSS Score'])
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
context 'when no custom field name is provided' do
|
|
120
|
-
let(:column_mappings) do
|
|
121
|
-
{
|
|
122
|
-
'0' => { 'type' => 'identifier' },
|
|
123
|
-
'1' => { 'type' => 'issue', 'field' => 'Custom Field', 'custom_field' => '' },
|
|
124
|
-
'3' => { 'type' => 'skip' }
|
|
125
|
-
}
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
it 'does not store a field for that column' do
|
|
129
|
-
save
|
|
130
|
-
|
|
131
|
-
issue_mapping = Mapping.find_by(
|
|
132
|
-
component: 'csv', source: issue_source, destination: destination
|
|
133
|
-
)
|
|
134
|
-
expect(issue_mapping.mapping_fields.pluck(:destination_field)).to eq(['plugin_id'])
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|