dradis-projects 3.0.1 → 3.6.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 +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
|