From 4b26ee2de6e54ab0644d24274d394c74abd26c4e Mon Sep 17 00:00:00 2001 From: Caitlin Date: Wed, 13 Dec 2023 15:00:06 -0500 Subject: [PATCH 01/11] add suffix to duplicate template names instead of overwriting them --- app/jobs/kit_import_job.rb | 25 +++++++++++++++++++------ spec/jobs/kit_import_job_spec.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index dedff4260..c70347a7d 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -107,10 +107,15 @@ def import_project_package end def import_plugin_templates - return unless File.directory?("#{working_dir}/kit/templates/plugins/") + template_directory = "#{working_dir}/kit/templates/plugins/" + return unless File.directory?(template_directory) logger.info { 'Copying Plugin Manager templates...' } - import_templates('plugins') + + FileUtils.cp_r( + "#{template_directory}/.", + Configuration.send('paths_templates_plugins') + ) end def import_project_templates @@ -178,10 +183,18 @@ def import_templates(template_type) template_directory = "#{working_dir}/kit/templates/#{template_type}" return unless Dir.exist?(template_directory) - FileUtils.cp_r( - "#{template_directory}/.", - Configuration.send("paths_templates_#{template_type}") - ) + Dir["#{template_directory}/*"].each do |file| + return unless File.file?(file) + file_name = NamingService.name_file( + original_filename: File.basename(file), + pathname: Pathname.new(Configuration.send("paths_templates_#{template_type}")) + ) + + FileUtils.cp( + file, + File.join(Configuration.send("paths_templates_#{template_type}"), file_name) + ) + end end def unzip(file) diff --git a/spec/jobs/kit_import_job_spec.rb b/spec/jobs/kit_import_job_spec.rb index 1d21bc486..904b695cd 100644 --- a/spec/jobs/kit_import_job_spec.rb +++ b/spec/jobs/kit_import_job_spec.rb @@ -76,6 +76,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') + 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...')) From 29482ba96a9a862977018fd26a5856da780fdf32 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Wed, 13 Dec 2023 15:08:59 -0500 Subject: [PATCH 02/11] changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 1c9622d0c..6ee1f4a68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ - Revision history: Improve version history for content with carriage return - Tylium: Show liquid content in editor preview - Web-server: Replace unicorn with puma in production + - Kit Import: Use file name sequencing when a template file with the same name exists - Upgraded gems: - rails - Bugs fixes: From 3545279ca2b180d5db75ebebcb7e9c7b712bea4a Mon Sep 17 00:00:00 2001 From: Caitlin Date: Wed, 13 Dec 2023 15:49:18 -0500 Subject: [PATCH 03/11] store configured template directories in a hash to be dynamically accessed --- app/jobs/kit_import_job.rb | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index c70347a7d..263e542f1 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -17,6 +17,11 @@ def perform(file_or_folder, logger:, user_id: nil) @logger = logger @project = nil @report_templates_dir = Configuration.paths_templates_reports + @templates_dirs = { + 'projects' => ProjectTemplate.pwd, + 'notes' => NoteTemplate.pwd, + 'methodologies' => Methodology.pwd + } @working_dir = Dir.mktmpdir @word_rtp = nil @@ -42,7 +47,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, :report_templates_dir, :templates_dirs, :working_dir def assign_project_rtp logger.info { 'Assigning RTP to project...' } @@ -180,19 +185,20 @@ def import_rules end def import_templates(template_type) - template_directory = "#{working_dir}/kit/templates/#{template_type}" - return unless Dir.exist?(template_directory) + template_wd = "#{working_dir}/kit/templates/#{template_type}" + return unless Dir.exist?(template_wd) + template_pwd = templates_dirs[template_type] - Dir["#{template_directory}/*"].each do |file| + Dir["#{template_wd}/*"].each do |file| return unless File.file?(file) file_name = NamingService.name_file( original_filename: File.basename(file), - pathname: Pathname.new(Configuration.send("paths_templates_#{template_type}")) + pathname: template_pwd ) FileUtils.cp( file, - File.join(Configuration.send("paths_templates_#{template_type}"), file_name) + File.join(template_pwd, file_name) ) end end From 8a80cc0ca7480f7badc27d0ace71e0a5a361fa56 Mon Sep 17 00:00:00 2001 From: Aaron Manaloto Date: Mon, 18 Dec 2023 21:23:50 +0800 Subject: [PATCH 04/11] Rename variable for clarity --- app/jobs/kit_import_job.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index 263e542f1..3d3761d60 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -185,11 +185,11 @@ def import_rules end def import_templates(template_type) - template_wd = "#{working_dir}/kit/templates/#{template_type}" - return unless Dir.exist?(template_wd) + kit_template_directory = "#{working_dir}/kit/templates/#{template_type}" + return unless Dir.exist?(kit_template_directory) template_pwd = templates_dirs[template_type] - Dir["#{template_wd}/*"].each do |file| + Dir["#{kit_template_directory}/*"].each do |file| return unless File.file?(file) file_name = NamingService.name_file( original_filename: File.basename(file), From 4782e29f3fa5e0cf3a977454425a5c6f530844da Mon Sep 17 00:00:00 2001 From: Aaron Manaloto Date: Thu, 21 Dec 2023 14:51:55 +0800 Subject: [PATCH 05/11] Consolidate to import_templates method and use consistent pathnames --- app/jobs/kit_import_job.rb | 48 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index 3d3761d60..4e041d9af 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 plugins projects } queue_as :dradis_upload @@ -17,11 +18,12 @@ def perform(file_or_folder, logger:, user_id: nil) @logger = logger @project = nil @report_templates_dir = Configuration.paths_templates_reports - @templates_dirs = { - 'projects' => ProjectTemplate.pwd, - 'notes' => NoteTemplate.pwd, - 'methodologies' => Methodology.pwd - } + @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 @@ -112,15 +114,8 @@ def import_project_package end def import_plugin_templates - template_directory = "#{working_dir}/kit/templates/plugins/" - return unless File.directory?(template_directory) - logger.info { 'Copying Plugin Manager templates...' } - - FileUtils.cp_r( - "#{template_directory}/.", - Configuration.send('paths_templates_plugins') - ) + import_templates('plugins') end def import_project_templates @@ -185,21 +180,22 @@ def import_rules end def import_templates(template_type) - kit_template_directory = "#{working_dir}/kit/templates/#{template_type}" - return unless Dir.exist?(kit_template_directory) + kit_template_dir = "#{working_dir}/kit/templates/#{template_type}" + return unless Dir.exist?(kit_template_dir) template_pwd = templates_dirs[template_type] - Dir["#{kit_template_directory}/*"].each do |file| - return unless File.file?(file) - file_name = NamingService.name_file( - original_filename: File.basename(file), - pathname: template_pwd - ) - - FileUtils.cp( - file, - File.join(template_pwd, file_name) - ) + if template_type == 'plugins' + FileUtils.cp_r("#{kit_template_dir}/.", template_pwd) + else + Dir["#{kit_template_dir}/*"].each do |file| + return unless File.file?(file) + file_name = NamingService.name_file( + original_filename: File.basename(file), + pathname: template_pwd + ) + + FileUtils.cp(file, "#{template_pwd}/#{file_name}") + end end end From b2d92769d9fc81efe88b8459ec480fc7b6dca122 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Wed, 26 Jun 2024 15:11:34 -0400 Subject: [PATCH 06/11] extract file naming to helper, remove plugins step from job and specs --- app/jobs/kit_import_job.rb | 50 +++++++++++++------------- spec/fixtures/files/templates/kit.zip | Bin 47039 -> 42228 bytes spec/jobs/kit_import_job_spec.rb | 7 ++-- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index 10ffe4503..f2ba9f5c5 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -4,7 +4,7 @@ class KitImportJob < ApplicationJob 'html_export' => ['html.erb'], 'word' => ['docm', 'docx'] } - TEMPLATE_TYPES = %w{ methodologies notes plugins projects } + TEMPLATE_TYPES = %w{ methodologies notes projects reports } queue_as :dradis_upload @@ -17,7 +17,6 @@ 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, @@ -31,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 @@ -39,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 @@ -49,7 +48,7 @@ def perform(file_or_folder, logger:, user_id: nil) end private - attr_reader :current_user, :logger, :report_templates_dir, :templates_dirs, :working_dir + attr_reader :current_user, :logger, :templates_dirs, :working_dir def assign_project_rtp logger.info { 'Assigning RTP to project...' } @@ -69,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') @@ -113,11 +118,6 @@ def import_project_package logger.info { " - New Project #{@project.id} created." } end - def import_plugin_templates - logger.info { 'Copying Plugin Manager templates...' } - import_templates('plugins') - end - def import_project_templates logger.info { 'Copying project templates...' } import_templates('projects') @@ -126,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 @@ -149,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" @@ -181,24 +181,24 @@ def import_rules def import_templates(template_type) kit_template_dir = "#{working_dir}/kit/templates/#{template_type}" + destination = templates_dirs[template_type] return unless Dir.exist?(kit_template_dir) - template_pwd = templates_dirs[template_type] - if template_type == 'plugins' - FileUtils.cp_r("#{kit_template_dir}/.", template_pwd) - else - Dir["#{kit_template_dir}/*"].each do |file| - return unless File.file?(file) - file_name = NamingService.name_file( - original_filename: File.basename(file), - pathname: template_pwd - ) - - FileUtils.cp(file, "#{template_pwd}/#{file_name}") - end + 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 + def name_file(original_filename, pathname) + NamingService.name_file( + original_filename: original_filename, + pathname: pathname + ) + end + def unzip(file) logger.info { 'Extracting zip file...' } diff --git a/spec/fixtures/files/templates/kit.zip b/spec/fixtures/files/templates/kit.zip index f9315474301e8623d667d3c8607d3ba2259e9ed4..74e33a240060b23aa16feb0ef607ef6284172aac 100644 GIT binary patch delta 24881 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 delta 29661 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

T#=Z5HrzW=oe-XYS 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 diff --git a/spec/jobs/kit_import_job_spec.rb b/spec/jobs/kit_import_job_spec.rb index 904b695cd..f548a44e0 100644 --- a/spec/jobs/kit_import_job_spec.rb +++ b/spec/jobs/kit_import_job_spec.rb @@ -4,7 +4,7 @@ RSpec.describe KitImportJob do before do - @user = create(:user) + @user = create(:user) file = File.new(Rails.root.join('spec', 'fixtures', 'files', 'templates', 'kit.zip')) @tmp_dir = Rails.root.join('tmp', 'rspec') @@ -14,7 +14,7 @@ FileUtils.cp file.path, @tmp_dir @tmp_file = File.new(@tmp_dir.join('kit.zip')) - ['methodologies', 'notes', 'plugins', 'projects', 'reports'].each do |item| + ['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 @@ -55,9 +55,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 From 4e7c20c9d1eb653758e19e79e94bb2501eace6a4 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Wed, 26 Jun 2024 15:34:31 -0400 Subject: [PATCH 07/11] add kit upload macros and simplify specs --- spec/jobs/kit_import_job_spec.rb | 33 ++++----------------------- spec/support/kit_upload_macros.rb | 37 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 29 deletions(-) create mode 100644 spec/support/kit_upload_macros.rb diff --git a/spec/jobs/kit_import_job_spec.rb b/spec/jobs/kit_import_job_spec.rb index f548a44e0..c1e4e16b6 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 + include KitUploadMacros + 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', '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) - ) + 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 diff --git a/spec/support/kit_upload_macros.rb b/spec/support/kit_upload_macros.rb new file mode 100644 index 000000000..fca577660 --- /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', '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 + + 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 From c4ef859cdfa5989c54456bdca9468028d22087e0 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Wed, 26 Jun 2024 16:36:31 -0400 Subject: [PATCH 08/11] use exist instead of file.file? --- app/jobs/kit_import_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index f2ba9f5c5..93ea6ff7c 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -185,7 +185,7 @@ def import_templates(template_type) return unless Dir.exist?(kit_template_dir) Dir["#{kit_template_dir}/*"].each do |file| - return unless File.file?(file) + return unless File.exist?(file) file_name = name_file(File.basename(file), destination) FileUtils.cp(file, "#{destination}/#{file_name}") From 742c1be8368207818eb117509efcd96a9ec85b09 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Thu, 27 Jun 2024 11:12:21 -0400 Subject: [PATCH 09/11] remove plugins from spec setup and use file.file? --- app/jobs/kit_import_job.rb | 2 +- spec/support/kit_upload_macros.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index 93ea6ff7c..f2ba9f5c5 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -185,7 +185,7 @@ def import_templates(template_type) return unless Dir.exist?(kit_template_dir) Dir["#{kit_template_dir}/*"].each do |file| - return unless File.exist?(file) + return unless File.file?(file) file_name = name_file(File.basename(file), destination) FileUtils.cp(file, "#{destination}/#{file_name}") diff --git a/spec/support/kit_upload_macros.rb b/spec/support/kit_upload_macros.rb index fca577660..b42bf7f39 100644 --- a/spec/support/kit_upload_macros.rb +++ b/spec/support/kit_upload_macros.rb @@ -10,7 +10,7 @@ def setup_kit_import FileUtils.cp file.path, @tmp_dir @tmp_file = File.new(@tmp_dir.join('kit.zip')) - ['methodologies', 'notes', 'plugins', 'projects', 'reports'].each do |item| + ['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 From 3fffcf1fe6314fcff06f259d909c4c090437a8c9 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Thu, 27 Jun 2024 11:29:58 -0400 Subject: [PATCH 10/11] fix specs by adding methodology content --- spec/jobs/kit_import_job_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/jobs/kit_import_job_spec.rb b/spec/jobs/kit_import_job_spec.rb index c1e4e16b6..46fb9a1d6 100644 --- a/spec/jobs/kit_import_job_spec.rb +++ b/spec/jobs/kit_import_job_spec.rb @@ -67,7 +67,7 @@ end it 'renames methodology templates if template with same name already exists' do - methodology = Methodology.new(filename: 'OWASPv4_Testing_Methodology') + methodology = Methodology.new(filename: 'OWASPv4_Testing_Methodology', content: '') methodology.save described_class.new.perform(@tmp_file, logger: Log.new.write('Testing...')) From 5ee408e78a7977cd24940e9c5e21a3d11b7ed75c Mon Sep 17 00:00:00 2001 From: Caitlin Date: Mon, 26 Aug 2024 12:57:02 -0400 Subject: [PATCH 11/11] name and copy file in helper --- app/jobs/kit_import_job.rb | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/app/jobs/kit_import_job.rb b/app/jobs/kit_import_job.rb index f2ba9f5c5..cc390fe8c 100644 --- a/app/jobs/kit_import_job.rb +++ b/app/jobs/kit_import_job.rb @@ -56,6 +56,17 @@ def assign_project_rtp @project.update_attribute :report_template_properties_id, @word_rtp.id if @word_rtp end + def copy_file(file, destination) + return unless File.file?(file) + + file_name = NamingService.name_file( + original_filename: File.basename(file), + pathname: destination + ) + + FileUtils.cp(file, "#{destination}/#{file_name}") + end + def copy_kit_to_working_dir(source) if File.file?(source) FileUtils.cp source, working_dir @@ -185,20 +196,10 @@ def import_templates(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}") + copy_file(file, destination) end end - def name_file(original_filename, pathname) - NamingService.name_file( - original_filename: original_filename, - pathname: pathname - ) - end - def unzip(file) logger.info { 'Extracting zip file...' }