diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-21 21:01:30 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-21 21:01:30 +0200 |
| commit | 1791d8067d00dc1381b9cdc3cc4ad44c1f6c7197 (patch) | |
| tree | 7046ee2744b42a7f0fc710a50fb36f4ab2bf0d19 | |
| parent | 65da515e27939c90a66ec3b063b5e58943d3dcea (diff) | |
Add storage isolation for tests, preventing live data destruction
| -rw-r--r-- | app/models/concerns/file_attachment.rb | 20 | ||||
| -rw-r--r-- | test/controllers/assets_controller_test.rb | 16 |
2 files changed, 21 insertions, 15 deletions
diff --git a/app/models/concerns/file_attachment.rb b/app/models/concerns/file_attachment.rb index e7a33c5..548531f 100644 --- a/app/models/concerns/file_attachment.rb +++ b/app/models/concerns/file_attachment.rb | |||
| @@ -66,12 +66,23 @@ module FileAttachment | |||
| 66 | @upload = UploadProxy.new(self) | 66 | @upload = UploadProxy.new(self) |
| 67 | end | 67 | end |
| 68 | 68 | ||
| 69 | class_methods do | ||
| 70 | def upload_root | ||
| 71 | Rails.env.test? ? Rails.root.join("tmp", "test_uploads") : Rails.root.join("public", "system", "uploads") | ||
| 72 | end | ||
| 73 | end | ||
| 74 | |||
| 75 | def upload_root | ||
| 76 | self.class.upload_root | ||
| 77 | end | ||
| 78 | |||
| 69 | def process_upload | 79 | def process_upload |
| 70 | return unless @pending_upload | 80 | return unless @pending_upload |
| 71 | uploaded_file = @pending_upload | 81 | uploaded_file = @pending_upload |
| 72 | @pending_upload = nil | 82 | @pending_upload = nil |
| 73 | 83 | ||
| 74 | old_dir = Rails.root.join("public", "system", "uploads", id.to_s) | 84 | old_dir = upload_root.join(id.to_s) |
| 85 | |||
| 75 | FileUtils.rm_rf(old_dir) if Dir.exist?(old_dir) | 86 | FileUtils.rm_rf(old_dir) if Dir.exist?(old_dir) |
| 76 | 87 | ||
| 77 | original_path = file_path(:original) | 88 | original_path = file_path(:original) |
| @@ -102,15 +113,12 @@ module FileAttachment | |||
| 102 | end | 113 | end |
| 103 | 114 | ||
| 104 | def delete_upload_files | 115 | def delete_upload_files |
| 105 | dir = Rails.root.join("public", "system", "uploads", id.to_s) | 116 | dir = upload_root.join(id.to_s) |
| 106 | FileUtils.rm_rf(dir) if Dir.exist?(dir) | 117 | FileUtils.rm_rf(dir) if Dir.exist?(dir) |
| 107 | end | 118 | end |
| 108 | 119 | ||
| 109 | def file_path(style) | 120 | def file_path(style) |
| 110 | Rails.root.join( | 121 | upload_root.join(id.to_s, style.to_s, variant_filename(style)).to_s |
| 111 | "public", "system", "uploads", | ||
| 112 | id.to_s, style.to_s, upload_file_name | ||
| 113 | ).to_s | ||
| 114 | end | 122 | end |
| 115 | 123 | ||
| 116 | def sanitize_filename(filename) | 124 | def sanitize_filename(filename) |
diff --git a/test/controllers/assets_controller_test.rb b/test/controllers/assets_controller_test.rb index 5f5f6e5..59ebab5 100644 --- a/test/controllers/assets_controller_test.rb +++ b/test/controllers/assets_controller_test.rb | |||
| @@ -4,17 +4,16 @@ class AssetsControllerTest < ActionController::TestCase | |||
| 4 | 4 | ||
| 5 | def setup | 5 | def setup |
| 6 | login_as :quentin | 6 | login_as :quentin |
| 7 | @existing_asset_ids = Asset.pluck(:id) | ||
| 7 | end | 8 | end |
| 8 | 9 | ||
| 9 | def teardown | 10 | def teardown |
| 10 | # Clean up any files written to disk during tests | 11 | (Asset.pluck(:id) - @existing_asset_ids).each do |id| |
| 11 | Dir.glob(Rails.root.join('public', 'system', 'uploads', 'test_*')).each do |dir| | 12 | dir = Asset.upload_root.join(id.to_s) |
| 13 | raise "Refusing to delete #{dir} -- outside tmp/, Rails.env.test? may be false" unless | ||
| 14 | dir.to_s.start_with?(Rails.root.join("tmp").to_s) | ||
| 12 | FileUtils.rm_rf(dir) | 15 | FileUtils.rm_rf(dir) |
| 13 | end | 16 | end |
| 14 | # Remove uploads created for assets created during tests | ||
| 15 | Asset.where("upload_file_name IS NOT NULL").where("id > 1000000").each do |a| | ||
| 16 | FileUtils.rm_rf(Rails.root.join('public', 'system', 'uploads', a.id.to_s)) | ||
| 17 | end | ||
| 18 | end | 17 | end |
| 19 | 18 | ||
| 20 | # --- index --- | 19 | # --- index --- |
| @@ -64,8 +63,7 @@ class AssetsControllerTest < ActionController::TestCase | |||
| 64 | 63 | ||
| 65 | # original and all four variants should exist on disk | 64 | # original and all four variants should exist on disk |
| 66 | %w[original medium thumb headline large].each do |style| | 65 | %w[original medium thumb headline large].each do |style| |
| 67 | path = Rails.root.join('public', 'system', 'uploads', | 66 | path = asset.send(:file_path, style) |
| 68 | asset.id.to_s, style, 'test_image.png') | ||
| 69 | assert File.exist?(path), "Expected #{style} variant at #{path}" | 67 | assert File.exist?(path), "Expected #{style} variant at #{path}" |
| 70 | end | 68 | end |
| 71 | end | 69 | end |
| @@ -137,7 +135,7 @@ class AssetsControllerTest < ActionController::TestCase | |||
| 137 | ) | 135 | ) |
| 138 | post :create, params: { asset: { name: 'To be deleted', upload: uploaded } } | 136 | post :create, params: { asset: { name: 'To be deleted', upload: uploaded } } |
| 139 | asset = Asset.last | 137 | asset = Asset.last |
| 140 | upload_dir = Rails.root.join('public', 'system', 'uploads', asset.id.to_s) | 138 | upload_dir = asset.send(:upload_root).join(asset.id.to_s) |
| 141 | assert Dir.exist?(upload_dir), "Upload directory should exist before destroy" | 139 | assert Dir.exist?(upload_dir), "Upload directory should exist before destroy" |
| 142 | 140 | ||
| 143 | assert_difference 'Asset.count', -1 do | 141 | assert_difference 'Asset.count', -1 do |
