diff --git a/CHANGELOG b/CHANGELOG index 03fff8c2a..54b79ae65 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ [v#.#.#] ([month] [YYYY]) - Attachments: Copy attachments when moving an evidence/note - Liquid: Make project-level collections available for Liquid syntax + - Kit Import: Use file name sequencing when a template file with the same name exists - Upgraded gems: nokogiri, rails, rexml - Bugs fixes: - Navigation: Restore functionality of native browser back/forward buttons diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index b49cceb23..f2ba9f5c5 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -4,6 +4,7 @@ class KitImportJob < ApplicationJob 'html_export' => ['html.erb'], 'word' => ['docm', 'docx'] } + TEMPLATE_TYPES = %w{ methodologies notes projects reports } queue_as :dradis_upload @@ -16,7 +17,12 @@ def perform(file_or_folder, logger:, user_id: nil) @current_user = user_id ? User.find(user_id) : User.first @logger = logger @project = nil - @report_templates_dir = Configuration.paths_templates_reports + @templates_dirs = TEMPLATE_TYPES.map do |template_type| + [ + template_type, + Pathname.new(Configuration.send("paths_templates_#{template_type}")) + ] + end.to_h @working_dir = Dir.mktmpdir @word_rtp = nil @@ -24,7 +30,6 @@ def perform(file_or_folder, logger:, user_id: nil) import_methodology_templates import_note_templates - import_plugin_templates import_project_package import_project_templates import_report_template_files @@ -32,6 +37,7 @@ def perform(file_or_folder, logger:, user_id: nil) if defined?(Dradis::Pro) import_report_template_properties import_rules + import_mappings assign_project_rtp end @@ -42,7 +48,7 @@ def perform(file_or_folder, logger:, user_id: nil) end private - attr_reader :current_user, :logger, :report_templates_dir, :working_dir + attr_reader :current_user, :logger, :templates_dirs, :working_dir def assign_project_rtp logger.info { 'Assigning RTP to project...' } @@ -62,6 +68,12 @@ def copy_kit_to_working_dir(source) end end + def import_mappings + logger.info { 'Adding Mappings...' } + mappings_seed = "#{working_dir}/kit/mappings_seed.rb" + load mappings_seed if File.exist?(mappings_seed) + end + def import_methodology_templates logger.info { 'Copying methodology templates...' } import_templates('methodologies') @@ -106,13 +118,6 @@ def import_project_package logger.info { " - New Project #{@project.id} created." } end - def import_plugin_templates - return unless File.directory?("#{working_dir}/kit/templates/plugins/") - - logger.info { 'Copying Plugin Manager templates...' } - import_templates('plugins') - end - def import_project_templates logger.info { 'Copying project templates...' } import_templates('projects') @@ -121,13 +126,13 @@ def import_project_templates def import_report_template_files logger.info { 'Copying report template files...' } - FileUtils.mkdir_p report_templates_dir + FileUtils.mkdir_p templates_dirs['reports'] %w{ excel html_export word }.each do |plugin| - dest = "#{report_templates_dir}/#{plugin}/" + dest = "#{templates_dirs['reports']}/#{plugin}/" temp_plugin_path = "#{working_dir}/kit/templates/reports/#{plugin}/*" # Only allow certain file extensions @@ -144,7 +149,7 @@ def import_report_template_properties logger.info { 'Adding properties to report template files...' } Dradis::Plugins.with_feature(:rtp).each do |plugin| - Dir.glob(File.join(report_templates_dir, plugin.plugin_name.to_s, '*')) do |template| + Dir.glob(File.join(templates_dirs['reports'], plugin.plugin_name.to_s, '*')) do |template| basename = File.basename(template, '.*') reports_dir = "#{working_dir}/kit/templates/reports" default_properties = "#{reports_dir}/#{plugin.plugin_name}/#{basename}.rb" @@ -175,12 +180,22 @@ def import_rules end def import_templates(template_type) - template_directory = "#{working_dir}/kit/templates/#{template_type}" - return unless Dir.exist?(template_directory) + kit_template_dir = "#{working_dir}/kit/templates/#{template_type}" + destination = templates_dirs[template_type] + return unless Dir.exist?(kit_template_dir) + + Dir["#{kit_template_dir}/*"].each do |file| + return unless File.file?(file) + + file_name = name_file(File.basename(file), destination) + FileUtils.cp(file, "#{destination}/#{file_name}") + end + end - FileUtils.cp_r( - "#{template_directory}/.", - Configuration.send("paths_templates_#{template_type}") + def name_file(original_filename, pathname) + NamingService.name_file( + original_filename: original_filename, + pathname: pathname ) end diff --git a/spec/fixtures/files/templates/kit.zip b/spec/fixtures/files/templates/kit.zip index f93154743..74e33a240 100644 Binary files a/spec/fixtures/files/templates/kit.zip and b/spec/fixtures/files/templates/kit.zip differ diff --git a/spec/jobs/kit_import_job_spec.rb b/spec/jobs/kit_import_job_spec.rb index 1d21bc486..46fb9a1d6 100644 --- a/spec/jobs/kit_import_job_spec.rb +++ b/spec/jobs/kit_import_job_spec.rb @@ -3,41 +3,16 @@ require 'rails_helper' RSpec.describe KitImportJob do - before do - @user = create(:user) - - file = File.new(Rails.root.join('spec', 'fixtures', 'files', 'templates', 'kit.zip')) - @tmp_dir = Rails.root.join('tmp', 'rspec') - FileUtils.mkdir_p @tmp_dir - - # Use a temporary file for the job instead of the original fixture - FileUtils.cp file.path, @tmp_dir - @tmp_file = File.new(@tmp_dir.join('kit.zip')) - - ['methodologies', 'notes', 'plugins', 'projects', 'reports'].each do |item| - conf = Configuration.find_or_initialize_by(name: "admin:paths:templates:#{item}") - folder = @tmp_dir.join(item) - conf.value = folder - conf.save! - FileUtils.mkdir_p folder - end + include KitUploadMacros - allow(NoteTemplate).to receive(:pwd).and_return( - Pathname.new(Configuration.paths_templates_notes) - ) - allow(Methodology).to receive(:pwd).and_return( - Pathname.new(Configuration.paths_templates_methodologies) - ) - allow(ProjectTemplate).to receive(:pwd).and_return( - Pathname.new(Configuration.paths_templates_projects) - ) + before do + @user = create(:user) + setup_kit_import end describe '#perform' do after(:all) do - FileUtils.rm_rf(Dir.glob(Attachment.pwd + '*')) - FileUtils.rm_rf(Rails.root.join('tmp', 'rspec')) - Configuration.delete_by('name LIKE ?', 'admin:paths:%') + cleanup_kit_import end it 'imports kit content' do @@ -55,9 +30,6 @@ # project template expect(ProjectTemplate.find_template('dradis-template-welcome')).to_not be_nil - # plugin templates - expect(Dir[Configuration.paths_templates_plugins + '/nessus/*']).to_not be_empty - # report template files expect(File.exists?(Rails.root.join('tmp', 'rspec', 'reports', 'word', 'dradis_welcome_template.v0.5.docm'))).to eq true expect(File.exists?(Rails.root.join('tmp', 'rspec', 'reports', 'excel', 'dradis_template-excel-simple.v1.3.xlsx'))).to eq true @@ -76,6 +48,33 @@ expect(ProjectTemplate.find_template('dradis-template-no-methodologies')).to_not be_nil end + it 'renames project templates if template with same name already exists' do + project_template = ProjectTemplate.new(filename: 'dradis-template-welcome') + project_template.save + + described_class.new.perform(@tmp_file, logger: Log.new.write('Testing...')) + + expect(ProjectTemplate.find_template('dradis-template-welcome_copy-01')).to_not be_nil + end + + it 'renames note templates if template with same name already exists' do + note_template = NoteTemplate.new(filename: 'evidence') + note_template.save + + described_class.new.perform(@tmp_file, logger: Log.new.write('Testing...')) + + expect(NoteTemplate.find('evidence_copy-01')).to_not be_nil + end + + it 'renames methodology templates if template with same name already exists' do + methodology = Methodology.new(filename: 'OWASPv4_Testing_Methodology', content: '') + methodology.save + + described_class.new.perform(@tmp_file, logger: Log.new.write('Testing...')) + + expect(Methodology.find('OWASPv4_Testing_Methodology_copy-01')).to_not be_nil + end + if defined?(Dradis::Pro) it 'imports Pro-only content too' do described_class.new.perform(@tmp_file, logger: Log.new.write('Testing...')) diff --git a/spec/support/kit_upload_macros.rb b/spec/support/kit_upload_macros.rb new file mode 100644 index 000000000..b42bf7f39 --- /dev/null +++ b/spec/support/kit_upload_macros.rb @@ -0,0 +1,37 @@ +module KitUploadMacros + extend ActiveSupport::Concern + + def setup_kit_import + file = File.new(Rails.root.join('spec', 'fixtures', 'files', 'templates', 'kit.zip')) + @tmp_dir = Rails.root.join('tmp', 'rspec') + FileUtils.mkdir_p @tmp_dir + + # Use a temporary file for the job instead of the original fixture + FileUtils.cp file.path, @tmp_dir + @tmp_file = File.new(@tmp_dir.join('kit.zip')) + + ['methodologies', 'notes', 'projects', 'reports'].each do |item| + conf = Configuration.find_or_initialize_by(name: "admin:paths:templates:#{item}") + folder = @tmp_dir.join(item) + conf.value = folder + conf.save! + FileUtils.mkdir_p folder + end + + allow(NoteTemplate).to receive(:pwd).and_return( + Pathname.new(Configuration.paths_templates_notes) + ) + allow(Methodology).to receive(:pwd).and_return( + Pathname.new(Configuration.paths_templates_methodologies) + ) + allow(ProjectTemplate).to receive(:pwd).and_return( + Pathname.new(Configuration.paths_templates_projects) + ) + end + + def cleanup_kit_import + FileUtils.rm_rf(Dir.glob(Attachment.pwd + '*')) + FileUtils.rm_rf(Rails.root.join('tmp', 'rspec')) + Configuration.delete_by('name LIKE ?', 'admin:paths:%') + end +end