dradis-projects 3.0.1 → 3.6.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 +10 -0
- data/app/controllers/dradis/plugins/projects/packages_controller.rb +5 -9
- data/app/controllers/dradis/plugins/projects/templates_controller.rb +5 -7
- data/dradis-projects.gemspec +1 -1
- data/lib/dradis/plugins/projects.rb +4 -0
- data/lib/dradis/plugins/projects/engine.rb +10 -1
- data/lib/dradis/plugins/projects/export/package.rb +11 -6
- data/lib/dradis/plugins/projects/export/template.rb +10 -155
- data/lib/dradis/plugins/projects/export/v1/template.rb +167 -0
- data/lib/dradis/plugins/projects/gem_version.rb +2 -2
- data/lib/dradis/plugins/projects/upload/package.rb +11 -11
- data/lib/dradis/plugins/projects/upload/template.rb +37 -313
- data/lib/dradis/plugins/projects/upload/v1/template.rb +388 -0
- data/lib/tasks/thorfile.rb +25 -13
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cab66cd7298c8c99104ed76957913173bde0225
|
4
|
+
data.tar.gz: 7a230d20b6e4e54abba7962c2bee781d40753e91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c13c91fc60a01f1309dfb0e8071589e3fc8cac377542697c52e38eccb99e3aa314e4e4ef72a8bc35a4e7376900fecacc50c2de6c3689a0974ecf08e9d9bea40
|
7
|
+
data.tar.gz: 5da07252c8179dbfc343bf7134afe927a01b8e095a14a8ef85fcad4551ccff7c7bc6301a0321a293155a5c05550ccf1cf0b601becd8bc3d7e7fe27958baf9a20
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
## Dradis Framework 3.6 (March XX, 2017) ##
|
2
|
+
|
3
|
+
* Include file version in project template export.
|
4
|
+
|
5
|
+
* Stop using homegrown configuration and use `Rails.application.config`.
|
6
|
+
|
7
|
+
* Make the project template exporter / uploader configurable.
|
8
|
+
|
9
|
+
* Break down the #export and #parse methods into smaller tasks.
|
10
|
+
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module Dradis::Plugins::Projects
|
2
2
|
class PackagesController < Dradis::Plugins::Export::BaseController
|
3
3
|
def show
|
4
|
-
|
5
|
-
export_manager_hash = session[:export_manager].with_indifferent_access
|
6
|
-
content_service_class = export_manager_hash[:content_service].constantize
|
4
|
+
filename = Rails.root.join('tmp', 'dradis-export.zip')
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
)
|
6
|
+
options = export_options.merge(plugin: Dradis::Plugins::Projects)
|
7
|
+
exporter = Dradis::Plugins::Projects::Export::Package.new(options)
|
8
|
+
template = exporter.export(filename: filename)
|
11
9
|
|
12
|
-
|
13
|
-
template = exporter.export(export_manager_hash.merge(filename: package_file))
|
14
|
-
send_file(package_file)
|
10
|
+
send_file(filename)
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
@@ -1,15 +1,13 @@
|
|
1
1
|
module Dradis::Plugins::Projects
|
2
2
|
class TemplatesController < Dradis::Plugins::Export::BaseController
|
3
3
|
def show
|
4
|
-
#
|
5
|
-
|
6
|
-
content_service_class = export_manager_hash[:content_service].constantize
|
4
|
+
# this allows us to have different exporters in different editions
|
5
|
+
exporter_class = Rails.application.config.dradis.projects.template_exporter
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
options = export_options.merge(plugin: Dradis::Plugins::Projects)
|
8
|
+
exporter = exporter_class.new(options)
|
9
|
+
template = exporter.export
|
11
10
|
|
12
|
-
template = exporter.export(export_manager_hash)
|
13
11
|
send_data(template, filename: 'dradis-template.xml', type: :xml)
|
14
12
|
end
|
15
13
|
end
|
data/dradis-projects.gemspec
CHANGED
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency 'rake', '~> 10.0'
|
26
26
|
spec.add_development_dependency 'rspec'
|
27
27
|
|
28
|
-
spec.add_dependency 'dradis-plugins', '~> 3.
|
28
|
+
spec.add_dependency 'dradis-plugins', '~> 3.6'
|
29
29
|
spec.add_dependency 'rubyzip', '~> 1.2.1'
|
30
30
|
end
|
@@ -13,3 +13,7 @@ require 'dradis/plugins/projects/export/template'
|
|
13
13
|
require 'dradis/plugins/projects/upload/package'
|
14
14
|
require 'dradis/plugins/projects/upload/template'
|
15
15
|
require 'dradis/plugins/projects/version'
|
16
|
+
|
17
|
+
module Dradis::Plugins::Projects
|
18
|
+
ActiveSupport.run_load_hooks(:dradis_projects, self)
|
19
|
+
end
|
@@ -4,6 +4,8 @@ module Dradis
|
|
4
4
|
class Engine < ::Rails::Engine
|
5
5
|
isolate_namespace Dradis::Plugins::Projects
|
6
6
|
|
7
|
+
config.dradis.projects = ActiveSupport::OrderedOptions.new
|
8
|
+
|
7
9
|
include ::Dradis::Plugins::Base
|
8
10
|
description 'Save and restore project information'
|
9
11
|
provides :export, :upload
|
@@ -14,6 +16,13 @@ module Dradis
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
19
|
+
initializer "dradis-projects.set_configs" do |app|
|
20
|
+
options = app.config.dradis.projects
|
21
|
+
options.template_exporter ||= Dradis::Plugins::Projects::Export::V1::Template
|
22
|
+
options.template_uploader ||= Dradis::Plugins::Projects::Upload::V1::Template::Importer
|
23
|
+
end
|
24
|
+
|
25
|
+
|
17
26
|
# Because this plugin provides two export modules, we have to overwrite
|
18
27
|
# the default .uploaders() method.
|
19
28
|
#
|
@@ -28,4 +37,4 @@ module Dradis
|
|
28
37
|
end
|
29
38
|
end
|
30
39
|
end
|
31
|
-
end
|
40
|
+
end
|
@@ -4,15 +4,16 @@ module Dradis::Plugins::Projects::Export
|
|
4
4
|
# Create a new project export bundle. It will include an XML file with the
|
5
5
|
# contents of the repository (see db_only) and all the attachments that
|
6
6
|
# have been uploaded into the system.
|
7
|
-
def export(
|
8
|
-
raise ":filename not provided" unless
|
7
|
+
def export(args={})
|
8
|
+
raise ":filename not provided" unless args.key?(:filename)
|
9
9
|
|
10
|
-
filename =
|
11
|
-
logger =
|
10
|
+
filename = args[:filename]
|
11
|
+
logger = options.fetch(:logger, Rails.logger)
|
12
12
|
|
13
13
|
File.delete(filename) if File.exists?(filename)
|
14
14
|
|
15
15
|
logger.debug{ "Creating a new Zip file in #{filename}..." }
|
16
|
+
|
16
17
|
Zip::File.open(filename, Zip::File::CREATE) do |zipfile|
|
17
18
|
Node.all.each do |node|
|
18
19
|
node_path = Attachment.pwd.join(node.id.to_s)
|
@@ -24,12 +25,16 @@ module Dradis::Plugins::Projects::Export
|
|
24
25
|
end
|
25
26
|
|
26
27
|
logger.debug{ "\tAdding XML repository dump" }
|
27
|
-
|
28
|
-
|
28
|
+
|
29
|
+
exporter_class = Rails.application.config.dradis.projects.template_exporter
|
30
|
+
template_exporter = exporter_class.new(options)
|
31
|
+
template = template_exporter.export
|
32
|
+
|
29
33
|
zipfile.get_output_stream('dradis-repository.xml') { |out|
|
30
34
|
out << template
|
31
35
|
}
|
32
36
|
end
|
37
|
+
|
33
38
|
logger.debug{ 'Done.' }
|
34
39
|
end
|
35
40
|
|
@@ -2,10 +2,10 @@ module Dradis::Plugins::Projects::Export
|
|
2
2
|
class Template < Dradis::Plugins::Export::Base
|
3
3
|
# This method returns an XML representation of current repository which
|
4
4
|
# includes Categories, Nodes and Notes
|
5
|
-
def export(
|
5
|
+
def export(args={})
|
6
6
|
builder = Builder::XmlMarkup.new
|
7
7
|
builder.instruct!
|
8
|
-
result = builder.tag!('dradis-template') do |template_builder|
|
8
|
+
result = builder.tag!('dradis-template', version: version) do |template_builder|
|
9
9
|
build_nodes(template_builder)
|
10
10
|
build_issues(template_builder)
|
11
11
|
build_methodologies(template_builder)
|
@@ -16,158 +16,13 @@ module Dradis::Plugins::Projects::Export
|
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
19
|
-
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
activity_builder.user_email(user_email_for_activity(activity))
|
26
|
-
activity_builder.created_at(activity.created_at.to_i)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def build_categories(builder)
|
33
|
-
categories = []
|
34
|
-
categories << Category.issue if @issues.any?
|
35
|
-
categories += @nodes.map do |node|
|
36
|
-
node.notes.map { |note| note.category }.uniq
|
37
|
-
end.flatten.uniq
|
38
|
-
|
39
|
-
builder.categories do |categories_builder|
|
40
|
-
categories.each do |category|
|
41
|
-
categories_builder.category do |category_builder|
|
42
|
-
category_builder.id(category.id)
|
43
|
-
category_builder.name(category.name)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def build_evidence_for_node(builder, node)
|
50
|
-
builder.evidence do |evidences_builder|
|
51
|
-
node.evidence.each do |evidence|
|
52
|
-
evidences_builder.evidence do |evidence_builder|
|
53
|
-
evidence_builder.id(evidence.id)
|
54
|
-
evidence_builder.author(evidence.author)
|
55
|
-
evidence_builder.tag!('issue-id', evidence.issue_id)
|
56
|
-
evidence_builder.content do
|
57
|
-
evidence_builder.cdata!(evidence.content)
|
58
|
-
end
|
59
|
-
build_activities_for(evidence_builder, evidence)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def build_issues(builder)
|
66
|
-
@issues = Issue.where(node_id: Node.issue_library).includes(:activities)
|
67
|
-
|
68
|
-
builder.issues do |issues_builder|
|
69
|
-
@issues.each do |issue|
|
70
|
-
issues_builder.issue do |issue_builder|
|
71
|
-
issue_builder.id(issue.id)
|
72
|
-
issue_builder.author(issue.author)
|
73
|
-
issue_builder.text do
|
74
|
-
issue_builder.cdata!(issue.text)
|
75
|
-
end
|
76
|
-
build_activities_for(issue_builder, issue)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def build_methodologies(builder)
|
83
|
-
methodologies = Node.methodology_library.notes
|
84
|
-
builder.methodologies do |methodologies_builder|
|
85
|
-
methodologies.each do |methodology|
|
86
|
-
methodologies_builder.methodology do |methodology_builder|
|
87
|
-
methodology_builder.text do
|
88
|
-
methodology_builder.cdata!(methodology.text)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def build_nodes(builder)
|
96
|
-
@nodes = Node.includes(:activities, :evidence, :notes, evidence: [:activities], notes: [:activities, :category]).all.reject do |node|
|
97
|
-
[Node::Types::METHODOLOGY,
|
98
|
-
Node::Types::ISSUELIB].include?(node.type_id)
|
99
|
-
end
|
100
|
-
|
101
|
-
builder.nodes do |nodes_builder|
|
102
|
-
@nodes.each do |node|
|
103
|
-
nodes_builder.node do |node_builder|
|
104
|
-
node_builder.id(node.id)
|
105
|
-
node_builder.label(node.label)
|
106
|
-
node_builder.tag!('parent-id', node.parent_id)
|
107
|
-
node_builder.position(node.position)
|
108
|
-
node_builder.properties do
|
109
|
-
node_builder.cdata!(node.raw_properties)
|
110
|
-
end
|
111
|
-
node_builder.tag!('type-id', node.type_id)
|
112
|
-
# Notes
|
113
|
-
build_notes_for_node(node_builder, node)
|
114
|
-
# Evidence
|
115
|
-
build_evidence_for_node(node_builder, node)
|
116
|
-
build_activities_for(node_builder, node)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def build_notes_for_node(builder, node)
|
123
|
-
builder.notes do |notes_builder|
|
124
|
-
node.notes.each do |note|
|
125
|
-
notes_builder.note do |note_builder|
|
126
|
-
note_builder.id(note.id)
|
127
|
-
note_builder.author(note.author)
|
128
|
-
note_builder.tag!('category-id', note.category_id)
|
129
|
-
note_builder.text do
|
130
|
-
note_builder.cdata!(note.text)
|
131
|
-
end
|
132
|
-
build_activities_for(note_builder, note)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def build_tags(builder)
|
139
|
-
tags = Tag.all
|
140
|
-
builder.tags do |tags_builder|
|
141
|
-
tags.each do |tag|
|
142
|
-
tags_builder.tag do |tag_builder|
|
143
|
-
tag_builder.id(tag.id)
|
144
|
-
tag_builder.name(tag.name)
|
145
|
-
tag_builder.taggings do |taggings_builder|
|
146
|
-
tag.taggings.each do |tagging|
|
147
|
-
taggings_builder.tagging do |tagging_builder|
|
148
|
-
tagging_builder.tag!('taggable-id', tagging.taggable_id)
|
149
|
-
tagging_builder.tag!('taggable-type', tagging.taggable_type)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
# Cache user emails so we don't have to make an extra SQL request
|
160
|
-
# for every activity
|
161
|
-
def user_email_for_activity(activity)
|
162
|
-
return activity.user if activity.user.is_a?(String)
|
163
|
-
|
164
|
-
@user_emails ||= begin
|
165
|
-
User.select([:id, :email]).all.each_with_object({}) do |user, hash|
|
166
|
-
hash[user.id] = user.email
|
167
|
-
end
|
168
|
-
end
|
169
|
-
@user_emails[activity.user_id]
|
170
|
-
end
|
171
|
-
|
19
|
+
def build_categories(builder); raise NotImplementedError; end
|
20
|
+
def build_issues(builder); raise NotImplementedError; end
|
21
|
+
def build_methodologies(builder); raise NotImplementedError; end
|
22
|
+
def build_nodes(builder); raise NotImplementedError; end
|
23
|
+
def build_tags(builder); raise NotImplementedError; end
|
24
|
+
def version; raise NotImplementedError; end
|
172
25
|
end
|
173
26
|
end
|
27
|
+
|
28
|
+
require_relative 'v1/template'
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Dradis::Plugins::Projects::Export::V1
|
2
|
+
class Template < Dradis::Plugins::Projects::Export::Template
|
3
|
+
VERSION = 1
|
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
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_issues(builder)
|
53
|
+
@issues = Issue.where(node_id: Node.issue_library).includes(:activities)
|
54
|
+
|
55
|
+
builder.issues do |issues_builder|
|
56
|
+
@issues.each do |issue|
|
57
|
+
issues_builder.issue do |issue_builder|
|
58
|
+
issue_builder.id(issue.id)
|
59
|
+
issue_builder.author(issue.author)
|
60
|
+
issue_builder.text do
|
61
|
+
issue_builder.cdata!(issue.text)
|
62
|
+
end
|
63
|
+
build_activities_for(issue_builder, issue)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def build_methodologies(builder)
|
70
|
+
methodologies = Node.methodology_library.notes
|
71
|
+
builder.methodologies do |methodologies_builder|
|
72
|
+
methodologies.each do |methodology|
|
73
|
+
methodologies_builder.methodology do |methodology_builder|
|
74
|
+
methodology_builder.text do
|
75
|
+
methodology_builder.cdata!(methodology.text)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_nodes(builder)
|
83
|
+
@nodes = Node.includes(:activities, :evidence, :notes, evidence: [:activities], notes: [:activities, :category]).all.reject do |node|
|
84
|
+
[Node::Types::METHODOLOGY,
|
85
|
+
Node::Types::ISSUELIB].include?(node.type_id)
|
86
|
+
end
|
87
|
+
|
88
|
+
builder.nodes do |nodes_builder|
|
89
|
+
@nodes.each do |node|
|
90
|
+
nodes_builder.node do |node_builder|
|
91
|
+
node_builder.id(node.id)
|
92
|
+
node_builder.label(node.label)
|
93
|
+
node_builder.tag!('parent-id', node.parent_id)
|
94
|
+
node_builder.position(node.position)
|
95
|
+
node_builder.properties do
|
96
|
+
node_builder.cdata!(node.raw_properties)
|
97
|
+
end
|
98
|
+
node_builder.tag!('type-id', node.type_id)
|
99
|
+
# Notes
|
100
|
+
build_notes_for_node(node_builder, node)
|
101
|
+
# Evidence
|
102
|
+
build_evidence_for_node(node_builder, node)
|
103
|
+
build_activities_for(node_builder, node)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def build_notes_for_node(builder, node)
|
110
|
+
builder.notes do |notes_builder|
|
111
|
+
node.notes.each do |note|
|
112
|
+
notes_builder.note do |note_builder|
|
113
|
+
note_builder.id(note.id)
|
114
|
+
note_builder.author(note.author)
|
115
|
+
note_builder.tag!('category-id', note.category_id)
|
116
|
+
note_builder.text do
|
117
|
+
note_builder.cdata!(note.text)
|
118
|
+
end
|
119
|
+
build_activities_for(note_builder, note)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_tags(builder)
|
126
|
+
tags = Tag.all
|
127
|
+
builder.tags do |tags_builder|
|
128
|
+
tags.each do |tag|
|
129
|
+
tags_builder.tag do |tag_builder|
|
130
|
+
tag_builder.id(tag.id)
|
131
|
+
tag_builder.name(tag.name)
|
132
|
+
tag_builder.taggings do |taggings_builder|
|
133
|
+
tag.taggings.each do |tagging|
|
134
|
+
taggings_builder.tagging do |tagging_builder|
|
135
|
+
tagging_builder.tag!('taggable-id', tagging.taggable_id)
|
136
|
+
tagging_builder.tag!('taggable-type', tagging.taggable_type)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# Cache user emails so we don't have to make an extra SQL request
|
147
|
+
# for every activity
|
148
|
+
def user_email_for_activity(activity)
|
149
|
+
return activity.user if activity.user.is_a?(String)
|
150
|
+
|
151
|
+
@user_emails ||= begin
|
152
|
+
User.select([:id, :email]).all.each_with_object({}) do |user, hash|
|
153
|
+
hash[user.id] = user.email
|
154
|
+
end
|
155
|
+
end
|
156
|
+
@user_emails[activity.user_id]
|
157
|
+
end
|
158
|
+
|
159
|
+
# Use the class VERSION constant, but allow for subclasses to overwrite it.
|
160
|
+
#
|
161
|
+
# See:
|
162
|
+
# http://stackoverflow.com/questions/3174563/how-to-use-an-overridden-constant-in-an-inheritanced-class
|
163
|
+
def version
|
164
|
+
self.class::VERSION
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|