dradis-projects 4.7.0 → 4.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/app/controllers/dradis/plugins/projects/packages_controller.rb +6 -1
- data/app/controllers/dradis/plugins/projects/templates_controller.rb +6 -1
- data/app/views/dradis/plugins/projects/export/_index-content.html.erb +7 -7
- data/app/views/dradis/plugins/projects/export/_index-tabs.html.erb +1 -1
- data/dradis-projects.gemspec +2 -2
- data/lib/dradis/plugins/projects/engine.rb +2 -2
- data/lib/dradis/plugins/projects/export/template.rb +1 -3
- data/lib/dradis/plugins/projects/export/v1/template.rb +8 -0
- data/lib/dradis/plugins/projects/export/v2/template.rb +8 -0
- data/lib/dradis/plugins/projects/export/v3/template.rb +8 -0
- data/lib/dradis/plugins/projects/export/v4/template.rb +207 -0
- data/lib/dradis/plugins/projects/gem_version.rb +1 -1
- data/lib/dradis/plugins/projects/upload/template.rb +2 -4
- data/lib/dradis/plugins/projects/upload/v1/template.rb +8 -0
- data/lib/dradis/plugins/projects/upload/v2/template.rb +8 -0
- data/lib/dradis/plugins/projects/upload/v3/template.rb +8 -0
- data/lib/dradis/plugins/projects/upload/v4/template.rb +651 -0
- data/spec/fixtures/files/with_invalid_states.xml +111 -0
- data/spec/fixtures/files/with_states.xml +111 -0
- data/spec/lib/dradis/plugins/projects/export/v2/template_spec.rb +9 -1
- data/spec/lib/dradis/plugins/projects/export/v4/template_spec.rb +84 -0
- data/spec/lib/dradis/plugins/projects/upload/v1/template_spec.rb +8 -0
- data/spec/lib/dradis/plugins/projects/upload/v2/template_spec.rb +9 -1
- data/spec/lib/dradis/plugins/projects/upload/v4/template_spec.rb +168 -0
- metadata +20 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b7835a990963a1839fdd202a226846d24979d5ce56dc9991a0b33b08ca274a2
|
4
|
+
data.tar.gz: cb67cd3c48680a650e5ce2bff9a38abf23cc78cd6f7f00475b1043bd0a244184
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13d379353149b40944deabe88f5da8222a0174e6619f74748f60dc4e0242deb65e20ae977de65cc4b3cc79285a1fbe91168d624df78c604f39d1c2d0f8abc6e7
|
7
|
+
data.tar.gz: b9fe36e2bd9e28c9a242033a6bcb289f1058848e8912cc203711aebb20a518d4b8393cf5aebcd8721f2e66f72108d99ff1b7a2be1ce5edda8859e8777cfa35de
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
module Dradis::Plugins::Projects
|
2
2
|
class PackagesController < Dradis::Plugins::Export::BaseController
|
3
|
+
skip_before_action :validate_scope
|
4
|
+
|
3
5
|
def show
|
4
6
|
filename = Rails.root.join('tmp', 'dradis-export.zip')
|
5
7
|
|
6
|
-
options =
|
8
|
+
options = export_params.merge(
|
9
|
+
plugin: Dradis::Plugins::Projects,
|
10
|
+
scope: :all
|
11
|
+
)
|
7
12
|
exporter = Dradis::Plugins::Projects::Export::Package.new(options)
|
8
13
|
template = exporter.export(filename: filename)
|
9
14
|
|
@@ -1,10 +1,15 @@
|
|
1
1
|
module Dradis::Plugins::Projects
|
2
2
|
class TemplatesController < Dradis::Plugins::Export::BaseController
|
3
|
+
skip_before_action :validate_scope
|
4
|
+
|
3
5
|
def show
|
4
6
|
# this allows us to have different exporters in different editions
|
5
7
|
exporter_class = Rails.application.config.dradis.projects.template_exporter
|
6
8
|
|
7
|
-
options =
|
9
|
+
options = export_params.merge(
|
10
|
+
plugin: Dradis::Plugins::Projects,
|
11
|
+
scope: :all
|
12
|
+
)
|
8
13
|
exporter = exporter_class.new(options)
|
9
14
|
template = exporter.export
|
10
15
|
|
@@ -4,16 +4,16 @@
|
|
4
4
|
|
5
5
|
<h4 class="header-underline">Choose an export option</h4>
|
6
6
|
|
7
|
-
<div class="
|
8
|
-
<%= radio_button_tag :route, :package, true, :class => '
|
9
|
-
<label class="
|
7
|
+
<div class="form-check">
|
8
|
+
<%= radio_button_tag :route, :package, true, :class => 'form-check-input' %>
|
9
|
+
<label class="form-check-label" for='route_package'>Package</label>
|
10
10
|
</div>
|
11
11
|
|
12
|
-
<div class="
|
13
|
-
<%= radio_button_tag :route, :template, false, :class => '
|
14
|
-
<label class="
|
12
|
+
<div class="form-check">
|
13
|
+
<%= radio_button_tag :route, :template, false, :class => 'form-check-input' %>
|
14
|
+
<label class="form-check-label" for='route_template'>Template</label>
|
15
15
|
</div>
|
16
16
|
|
17
|
-
<button id="export-button" class="btn btn-lg btn-primary mt-4">Export</button>
|
17
|
+
<button id="export-button" class="btn btn-lg btn-primary mt-4">Export All Records</button>
|
18
18
|
<% end %>
|
19
19
|
<% end%>
|
data/dradis-projects.gemspec
CHANGED
@@ -22,9 +22,9 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 2.2'
|
24
24
|
spec.add_development_dependency 'combustion'
|
25
|
-
spec.add_development_dependency 'rake', '
|
25
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
26
26
|
spec.add_development_dependency 'rspec'
|
27
27
|
|
28
|
-
spec.add_dependency 'dradis-plugins', '
|
28
|
+
spec.add_dependency 'dradis-plugins', '>= 4.8.0'
|
29
29
|
spec.add_dependency 'rubyzip'
|
30
30
|
end
|
@@ -18,8 +18,8 @@ module Dradis
|
|
18
18
|
|
19
19
|
initializer "dradis-projects.set_configs" do |app|
|
20
20
|
options = app.config.dradis.projects
|
21
|
-
options.template_exporter ||= Dradis::Plugins::Projects::Export::
|
22
|
-
options.template_uploader ||= Dradis::Plugins::Projects::Upload::
|
21
|
+
options.template_exporter ||= Dradis::Plugins::Projects::Export::V4::Template
|
22
|
+
options.template_uploader ||= Dradis::Plugins::Projects::Upload::V4::Template::Importer
|
23
23
|
end
|
24
24
|
|
25
25
|
|
@@ -1,3 +1,11 @@
|
|
1
|
+
# DEPRECATED - this class is v1 of the Template Exporter and shouldn't be updated.
|
2
|
+
# V4 released on Apr 2022
|
3
|
+
# V1 can be removed on Apr 2024
|
4
|
+
#
|
5
|
+
# We're duplicating this file for v4, and even though the code lives in two
|
6
|
+
# places now, this file isn't expected to evolve and is now frozen to V1
|
7
|
+
# behavior.
|
8
|
+
|
1
9
|
module Dradis::Plugins::Projects::Export::V1
|
2
10
|
class Template < Dradis::Plugins::Projects::Export::Template
|
3
11
|
VERSION = 1
|
@@ -1,3 +1,11 @@
|
|
1
|
+
# DEPRECATED - this class is v2 of the Template Exporter and shouldn't be updated.
|
2
|
+
# V4 released on Apr 2022
|
3
|
+
# V2 can be removed on Apr 2024
|
4
|
+
#
|
5
|
+
# We're duplicating this file for v4, and even though the code lives in two
|
6
|
+
# places now, this file isn't expected to evolve and is now frozen to V2
|
7
|
+
# behavior.
|
8
|
+
|
1
9
|
module Dradis::Plugins::Projects::Export::V2
|
2
10
|
class Template < Dradis::Plugins::Projects::Export::V1::Template
|
3
11
|
VERSION = 2
|
@@ -1,3 +1,11 @@
|
|
1
|
+
# DEPRECATED - this class is v3 of the Template Exporter and shouldn't be updated.
|
2
|
+
# V4 released on Apr 2022
|
3
|
+
# V3 can be removed on Apr 2024
|
4
|
+
#
|
5
|
+
# We're duplicating this file for v4, and even though the code lives in two
|
6
|
+
# places now, this file isn't expected to evolve and is now frozen to V3
|
7
|
+
# behavior.
|
8
|
+
|
1
9
|
module Dradis::Plugins::Projects::Export::V3
|
2
10
|
class Template < Dradis::Plugins::Projects::Export::V2::Template
|
3
11
|
VERSION = 3
|
@@ -0,0 +1,207 @@
|
|
1
|
+
module Dradis::Plugins::Projects::Export::V4
|
2
|
+
class Template < Dradis::Plugins::Projects::Export::Template
|
3
|
+
VERSION = 4
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
def build_activities_for(builder, trackable)
|
8
|
+
builder.activities do |activities_builder|
|
9
|
+
trackable.activities.each do |activity|
|
10
|
+
activities_builder.activity do |activity_builder|
|
11
|
+
activity_builder.action(activity.action)
|
12
|
+
activity_builder.user_email(user_email_for_activity(activity))
|
13
|
+
activity_builder.created_at(activity.created_at.to_i)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_categories(builder)
|
20
|
+
categories = []
|
21
|
+
categories << Category.issue if @issues.any?
|
22
|
+
categories += @nodes.map do |node|
|
23
|
+
node.notes.map { |note| note.category }.uniq
|
24
|
+
end.flatten.uniq
|
25
|
+
|
26
|
+
builder.categories do |categories_builder|
|
27
|
+
categories.each do |category|
|
28
|
+
categories_builder.category do |category_builder|
|
29
|
+
category_builder.id(category.id)
|
30
|
+
category_builder.name(category.name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_evidence_for_node(builder, node)
|
37
|
+
builder.evidence do |evidences_builder|
|
38
|
+
node.evidence.each do |evidence|
|
39
|
+
evidences_builder.evidence do |evidence_builder|
|
40
|
+
evidence_builder.id(evidence.id)
|
41
|
+
evidence_builder.author(evidence.author)
|
42
|
+
evidence_builder.tag!('issue-id', evidence.issue_id)
|
43
|
+
evidence_builder.content do
|
44
|
+
evidence_builder.cdata!(evidence.content)
|
45
|
+
end
|
46
|
+
build_activities_for(evidence_builder, evidence)
|
47
|
+
build_comments_for(evidence_builder, evidence)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_issues(builder)
|
54
|
+
@issues = Issue.where(node_id: project.issue_library).includes(:activities)
|
55
|
+
|
56
|
+
builder.issues do |issues_builder|
|
57
|
+
@issues.each do |issue|
|
58
|
+
issues_builder.issue do |issue_builder|
|
59
|
+
issue_builder.id(issue.id)
|
60
|
+
issue_builder.author(issue.author)
|
61
|
+
issue_builder.state(issue.state)
|
62
|
+
issue_builder.text do
|
63
|
+
issue_builder.cdata!(issue.text)
|
64
|
+
end
|
65
|
+
build_activities_for(issue_builder, issue)
|
66
|
+
build_comments_for(issue_builder, issue)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_methodologies(builder)
|
73
|
+
methodologies = project.methodology_library.notes
|
74
|
+
builder.methodologies do |methodologies_builder|
|
75
|
+
methodologies.each do |methodology|
|
76
|
+
methodologies_builder.methodology(version: VERSION) do |methodology_builder|
|
77
|
+
methodology_builder.text do
|
78
|
+
methodology_builder.cdata!(methodology.text)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_nodes(builder)
|
86
|
+
@nodes = project.nodes.includes(:activities, :evidence, :notes, evidence: [:activities], notes: [:activities, :category]).all.reject do |node|
|
87
|
+
[Node::Types::METHODOLOGY,
|
88
|
+
Node::Types::ISSUELIB].include?(node.type_id)
|
89
|
+
end
|
90
|
+
|
91
|
+
builder.nodes do |nodes_builder|
|
92
|
+
@nodes.each do |node|
|
93
|
+
nodes_builder.node do |node_builder|
|
94
|
+
node_builder.id(node.id)
|
95
|
+
node_builder.label(node.label)
|
96
|
+
node_builder.tag!('parent-id', node.parent_id)
|
97
|
+
node_builder.position(node.position)
|
98
|
+
node_builder.properties do
|
99
|
+
node_builder.cdata!(node.raw_properties)
|
100
|
+
end
|
101
|
+
node_builder.tag!('type-id', node.type_id)
|
102
|
+
# Notes
|
103
|
+
build_notes_for_node(node_builder, node)
|
104
|
+
# Evidence
|
105
|
+
build_evidence_for_node(node_builder, node)
|
106
|
+
build_activities_for(node_builder, node)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_notes_for_node(builder, node)
|
113
|
+
builder.notes do |notes_builder|
|
114
|
+
node.notes.each do |note|
|
115
|
+
notes_builder.note do |note_builder|
|
116
|
+
note_builder.id(note.id)
|
117
|
+
note_builder.author(note.author)
|
118
|
+
note_builder.tag!('category-id', note.category_id)
|
119
|
+
note_builder.text do
|
120
|
+
note_builder.cdata!(note.text)
|
121
|
+
end
|
122
|
+
build_activities_for(note_builder, note)
|
123
|
+
build_comments_for(note_builder, note)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# No-op here, overwritten in PRO
|
130
|
+
def build_report_content(builder); end
|
131
|
+
|
132
|
+
def build_tags(builder)
|
133
|
+
tags = project.tags
|
134
|
+
builder.tags do |tags_builder|
|
135
|
+
tags.each do |tag|
|
136
|
+
tags_builder.tag do |tag_builder|
|
137
|
+
tag_builder.id(tag.id)
|
138
|
+
tag_builder.name(tag.name)
|
139
|
+
tag_builder.taggings do |taggings_builder|
|
140
|
+
tag.taggings.each do |tagging|
|
141
|
+
taggings_builder.tagging do |tagging_builder|
|
142
|
+
tagging_builder.tag!('taggable-id', tagging.taggable_id)
|
143
|
+
tagging_builder.tag!('taggable-type', tagging.taggable_type)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Cache user emails so we don't have to make an extra SQL request
|
154
|
+
# for every activity
|
155
|
+
def user_email_for_activity(activity)
|
156
|
+
return activity.user if activity.user.is_a?(String)
|
157
|
+
|
158
|
+
@user_emails ||= begin
|
159
|
+
User.select([:id, :email]).all.each_with_object({}) do |user, hash|
|
160
|
+
hash[user.id] = user.email
|
161
|
+
end
|
162
|
+
end
|
163
|
+
@user_emails[activity.user_id]
|
164
|
+
end
|
165
|
+
|
166
|
+
# Use the class VERSION constant, but allow for subclasses to overwrite it.
|
167
|
+
#
|
168
|
+
# See:
|
169
|
+
# http://stackoverflow.com/questions/3174563/how-to-use-an-overridden-constant-in-an-inheritanced-class
|
170
|
+
def version
|
171
|
+
self.class::VERSION
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# Export::V2::Template
|
176
|
+
#
|
177
|
+
def build_comments_for(builder, commentable)
|
178
|
+
builder.comments do |comments_builder|
|
179
|
+
commentable.comments.each do |comment|
|
180
|
+
comments_builder.comment do |comment_builder|
|
181
|
+
comment_builder.content do
|
182
|
+
comment_builder.cdata!(comment.content)
|
183
|
+
end
|
184
|
+
comment_builder.author(comment.user&.email)
|
185
|
+
comment_builder.created_at(comment.created_at.to_i)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Export::V3::Template
|
192
|
+
#
|
193
|
+
def build_methodologies(builder)
|
194
|
+
boards = content_service.all_boards
|
195
|
+
|
196
|
+
builder.methodologies do |methodologies_builder|
|
197
|
+
|
198
|
+
boards.each do |board|
|
199
|
+
node_id =
|
200
|
+
board.node == project.methodology_library ? nil : board.node_id
|
201
|
+
|
202
|
+
board.to_xml(methodologies_builder, includes: [:activities, :assignees, :comments], version: VERSION)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -33,7 +33,6 @@ module Dradis::Plugins::Projects::Upload
|
|
33
33
|
# table to re-associate the attachments in the project archive with the new
|
34
34
|
# node IDs in the current project.
|
35
35
|
def import(params={})
|
36
|
-
|
37
36
|
# load the template
|
38
37
|
logger.info { "Loading template file from: #{params[:file]}" }
|
39
38
|
template = Nokogiri::XML(File.read(params[:file]))
|
@@ -44,6 +43,7 @@ module Dradis::Plugins::Projects::Upload
|
|
44
43
|
return false
|
45
44
|
end
|
46
45
|
|
46
|
+
|
47
47
|
if template.xpath('/dradis-template').empty?
|
48
48
|
error = "The uploaded file doesn't look like a Dradis project template (/dradis-template)."
|
49
49
|
logger.fatal{ error }
|
@@ -91,6 +91,4 @@ module Dradis::Plugins::Projects::Upload
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
require_relative '
|
95
|
-
require_relative 'v2/template'
|
96
|
-
require_relative 'v3/template'
|
94
|
+
require_relative 'v4/template'
|
@@ -1,3 +1,11 @@
|
|
1
|
+
# DEPRECATED - this class is v1 of the Template Importer and shouldn't be updated.
|
2
|
+
# V4 released on Apr 2022
|
3
|
+
# V1 can be removed on Apr 2024
|
4
|
+
#
|
5
|
+
# We're duplicating this file for v4, and even though the code lives in two
|
6
|
+
# places now, this file isn't expected to evolve and is now frozen to V1
|
7
|
+
# behavior.
|
8
|
+
|
1
9
|
module Dradis::Plugins::Projects::Upload::V1
|
2
10
|
module Template
|
3
11
|
|
@@ -1,3 +1,11 @@
|
|
1
|
+
# DEPRECATED - this class is v2 of the Template Importer and shouldn't be updated.
|
2
|
+
# V4 released on Apr 2022
|
3
|
+
# V2 can be removed on Apr 2024
|
4
|
+
#
|
5
|
+
# We're duplicating this file for v4, and even though the code lives in two
|
6
|
+
# places now, this file isn't expected to evolve and is now frozen to V2
|
7
|
+
# behavior.
|
8
|
+
|
1
9
|
module Dradis::Plugins::Projects::Upload::V2
|
2
10
|
module Template
|
3
11
|
class Importer < Dradis::Plugins::Projects::Upload::V1::Template::Importer
|
@@ -1,3 +1,11 @@
|
|
1
|
+
# DEPRECATED - this class is v3 of the Template Importer and shouldn't be updated.
|
2
|
+
# V4 released on Apr 2022
|
3
|
+
# V3 can be removed on Apr 2024
|
4
|
+
#
|
5
|
+
# We're duplicating this file for v4, and even though the code lives in two
|
6
|
+
# places now, this file isn't expected to evolve and is now frozen to V3
|
7
|
+
# behavior.
|
8
|
+
|
1
9
|
module Dradis::Plugins::Projects::Upload::V3
|
2
10
|
module Template
|
3
11
|
class Importer < Dradis::Plugins::Projects::Upload::V2::Template::Importer
|