Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package rubygem-activestorage-8.0 for
openSUSE:Factory checked in at 2026-07-07 21:05:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-activestorage-8.0 (Old)
and /work/SRC/openSUSE:Factory/.rubygem-activestorage-8.0.new.1982 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-activestorage-8.0"
Tue Jul 7 21:05:05 2026 rev:6 rq:1364225 version:8.0.5
Changes:
--------
---
/work/SRC/openSUSE:Factory/rubygem-activestorage-8.0/rubygem-activestorage-8.0.changes
2025-10-10 17:13:51.732638133 +0200
+++
/work/SRC/openSUSE:Factory/.rubygem-activestorage-8.0.new.1982/rubygem-activestorage-8.0.changes
2026-07-07 21:07:50.319916306 +0200
@@ -1,0 +2,6 @@
+Tue Jul 7 09:05:53 UTC 2026 - Aleksei Burlakov <[email protected]>
+
+- Update to version 8.0.5:
+
https://rubyonrails.org/2026/3/24/Rails-Versions-8-0-5-and-8-1-3-have-been-released
+
+-------------------------------------------------------------------
Old:
----
activestorage-8.0.3.gem
New:
----
activestorage-8.0.5.gem
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ rubygem-activestorage-8.0.spec ++++++
--- /var/tmp/diff_new_pack.0Fj9RN/_old 2026-07-07 21:07:50.863935067 +0200
+++ /var/tmp/diff_new_pack.0Fj9RN/_new 2026-07-07 21:07:50.867935205 +0200
@@ -1,7 +1,7 @@
#
# spec file for package rubygem-activestorage-8.0
#
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
#
Name: rubygem-activestorage-8.0
-Version: 8.0.3
+Version: 8.0.5
Release: 0
%define mod_name activestorage
%define mod_full_name %{mod_name}-%{version}
++++++ activestorage-8.0.3.gem -> activestorage-8.0.5.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md 1980-01-02 01:00:00.000000000 +0100
+++ new/CHANGELOG.md 1980-01-02 01:00:00.000000000 +0100
@@ -1,3 +1,66 @@
+## Rails 8.0.5 (March 24, 2026) ##
+
+* Fix `ActiveStorage::Blob` content type predicate methods to handle `nil`.
+
+ *Daichi KUDO*
+
+
+## Rails 8.0.4.1 (March 23, 2026) ##
+
+* Filter user supplied metadata in DirectUploadController
+
+ [CVE-2026-33173]
+
+ *Jean Boussier*
+
+* Configurable maxmimum streaming chunk size
+
+ Makes sure that byte ranges for blobs don't exceed 100mb by default.
+ Content ranges that are too big can result in denial of service.
+
+ [CVE-2026-33174]
+
+ *Gannon McGibbon*
+
+* Limit range requests to a single range
+
+ [CVE-2026-33658]
+
+ *Jean Boussier*
+
+* Prevent path traversal in `DiskService`.
+
+ `DiskService#path_for` now raises an `InvalidKeyError` when passed keys
with dot segments (".",
+ ".."), or if the resolved path is outside the storage root directory.
+
+ `#path_for` also now consistently raises `InvalidKeyError` if the key is
invalid in any way, for
+ example containing null bytes or having an incompatible encoding.
Previously, the exception
+ raised may have been `ArgumentError` or `Encoding::CompatibilityError`.
+
+ `DiskController` now explicitly rescues `InvalidKeyError` with appropriate
HTTP status codes.
+
+ [CVE-2026-33195]
+
+ *Mike Dalessio*
+
+* Prevent glob injection in `DiskService#delete_prefixed`.
+
+ Escape glob metacharacters in the resolved path before passing to
`Dir.glob`.
+
+ Note that this change breaks any existing code that is relying on
`delete_prefixed` to expand
+ glob metacharacters. This change presumes that is unintended behavior (as
other storage services
+ do not respect these metacharacters).
+
+ [CVE-2026-33202]
+
+ *Mike Dalessio*
+
+
+## Rails 8.0.4 (October 28, 2025) ##
+
+* No changes.
+
+
## Rails 8.0.3 (September 22, 2025) ##
* Address deprecation of `Aws::S3::Object#upload_stream` in
`ActiveStorage::Service::S3Service`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/app/controllers/active_storage/disk_controller.rb
new/app/controllers/active_storage/disk_controller.rb
--- old/app/controllers/active_storage/disk_controller.rb 1980-01-02
01:00:00.000000000 +0100
+++ new/app/controllers/active_storage/disk_controller.rb 1980-01-02
01:00:00.000000000 +0100
@@ -17,6 +17,8 @@
end
rescue Errno::ENOENT
head :not_found
+ rescue ActiveStorage::InvalidKeyError
+ head :not_found
end
def update
@@ -32,6 +34,8 @@
end
rescue ActiveStorage::IntegrityError
head ActionDispatch::Constants::UNPROCESSABLE_CONTENT
+ rescue ActiveStorage::InvalidKeyError
+ head ActionDispatch::Constants::UNPROCESSABLE_CONTENT
end
private
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/app/controllers/concerns/active_storage/streaming.rb
new/app/controllers/concerns/active_storage/streaming.rb
--- old/app/controllers/concerns/active_storage/streaming.rb 1980-01-02
01:00:00.000000000 +0100
+++ new/app/controllers/concerns/active_storage/streaming.rb 1980-01-02
01:00:00.000000000 +0100
@@ -14,7 +14,8 @@
def send_blob_byte_range_data(blob, range_header, disposition: nil)
ranges = Rack::Utils.get_byte_ranges(range_header, blob.byte_size)
- return head(:range_not_satisfiable) if ranges.blank? ||
ranges.all?(&:blank?)
+ return head(:range_not_satisfiable) unless ranges_valid?(ranges)
+ return head(:range_not_satisfiable) if ranges.length >
ActiveStorage.streaming_max_ranges
if ranges.length == 1
range = ranges.first
@@ -51,6 +52,12 @@
)
end
+ def ranges_valid?(ranges)
+ return false if ranges.blank? || ranges.all?(&:blank?)
+
+ ranges.sum { |range| range.end - range.begin } <
ActiveStorage.streaming_chunk_max_size
+ end
+
# Stream the blob from storage directly to the response. The disposition
can be controlled by setting +disposition+.
# The content type and filename is set directly from the +blob+.
def send_blob_stream(blob, disposition: nil) # :doc:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/app/models/active_storage/blob.rb
new/app/models/active_storage/blob.rb
--- old/app/models/active_storage/blob.rb 1980-01-02 01:00:00.000000000
+0100
+++ new/app/models/active_storage/blob.rb 1980-01-02 01:00:00.000000000
+0100
@@ -16,10 +16,18 @@
# Blobs are intended to be immutable in as-so-far as their reference to a
specific file goes. You're allowed to
# update a blob's metadata on a subsequent pass, but you should not update the
key or change the uploaded file.
# If you need to create a derivative or otherwise change the blob, simply
create a new blob and purge the old one.
+#
+# When using a custom +key+, the value is treated as trusted. Using untrusted
user input
+# as the key may result in unexpected behavior.
class ActiveStorage::Blob < ActiveStorage::Record
MINIMUM_TOKEN_LENGTH = 28
has_secure_token :key, length: MINIMUM_TOKEN_LENGTH
+
+ # FIXME: these property should never have been stored in the metadata.
+ # The blob table should be migrated to have dedicated columns for theses.
+ PROTECTED_METADATA = %w(analyzed identified composed)
+ private_constant :PROTECTED_METADATA
store :metadata, accessors: [ :analyzed, :identified, :composed ], coder:
ActiveRecord::Coders::JSON
class_attribute :services, default: {}
@@ -92,6 +100,9 @@
# be saved before the upload begins to prevent the upload clobbering
another due to key collisions.
# When providing a content type, pass <tt>identify: false</tt> to bypass
# automatic content type inference.
+ #
+ # The optional +key+ parameter is treated as trusted. Using untrusted user
input
+ # as the key may result in unexpected behavior.
def create_and_upload!(key: nil, io:, filename:, content_type: nil,
metadata: nil, service_name: nil, identify: true, record: nil)
create_after_unfurling!(key: key, io: io, filename: filename,
content_type: content_type, metadata: metadata, service_name: service_name,
identify: identify).tap do |blob|
blob.upload_without_unfurling(io)
@@ -104,6 +115,7 @@
# Once the form using the direct upload is submitted, the blob can be
associated with the right record using
# the signed ID.
def create_before_direct_upload!(key: nil, filename:, byte_size:,
checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil)
+ metadata = filter_metadata(metadata)
create! key: key, filename: filename, byte_size: byte_size, checksum:
checksum, content_type: content_type, metadata: metadata, service_name:
service_name
end
@@ -151,6 +163,15 @@
combined_blob.save!
end
end
+
+ private
+ def filter_metadata(metadata)
+ if metadata.is_a?(Hash)
+ metadata.without(*PROTECTED_METADATA)
+ else
+ metadata
+ end
+ end
end
include Analyzable
@@ -189,22 +210,22 @@
# Returns true if the content_type of this blob is in the image range, like
image/png.
def image?
- content_type.start_with?("image")
+ content_type&.start_with?("image")
end
# Returns true if the content_type of this blob is in the audio range, like
audio/mpeg.
def audio?
- content_type.start_with?("audio")
+ content_type&.start_with?("audio")
end
# Returns true if the content_type of this blob is in the video range, like
video/mp4.
def video?
- content_type.start_with?("video")
+ content_type&.start_with?("video")
end
# Returns true if the content_type of this blob is in the text range, like
text/plain.
def text?
- content_type.start_with?("text")
+ content_type&.start_with?("text")
end
# Returns the URL of the blob on the service. This returns a permanent URL
for public files, and returns a
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/active_storage/engine.rb
new/lib/active_storage/engine.rb
--- old/lib/active_storage/engine.rb 1980-01-02 01:00:00.000000000 +0100
+++ new/lib/active_storage/engine.rb 1980-01-02 01:00:00.000000000 +0100
@@ -122,6 +122,7 @@
ActiveStorage.binary_content_type =
app.config.active_storage.binary_content_type || "application/octet-stream"
ActiveStorage.video_preview_arguments =
app.config.active_storage.video_preview_arguments || "-y -vframes 1 -f image2"
ActiveStorage.track_variants =
app.config.active_storage.track_variants || false
+ ActiveStorage.streaming_chunk_max_size =
app.config.active_storage.streaming_chunk_max_size || 100.megabytes
end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/active_storage/errors.rb
new/lib/active_storage/errors.rb
--- old/lib/active_storage/errors.rb 1980-01-02 01:00:00.000000000 +0100
+++ new/lib/active_storage/errors.rb 1980-01-02 01:00:00.000000000 +0100
@@ -26,4 +26,8 @@
# Raised when a Previewer is unable to generate a preview image.
class PreviewError < Error; end
+
+ # Raised when a storage key resolves to a path outside the service's root
+ # directory, indicating a potential path traversal attack.
+ class InvalidKeyError < Error; end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/active_storage/gem_version.rb
new/lib/active_storage/gem_version.rb
--- old/lib/active_storage/gem_version.rb 1980-01-02 01:00:00.000000000
+0100
+++ new/lib/active_storage/gem_version.rb 1980-01-02 01:00:00.000000000
+0100
@@ -9,7 +9,7 @@
module VERSION
MAJOR = 8
MINOR = 0
- TINY = 3
+ TINY = 5
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/active_storage/service/disk_service.rb
new/lib/active_storage/service/disk_service.rb
--- old/lib/active_storage/service/disk_service.rb 1980-01-02
01:00:00.000000000 +0100
+++ new/lib/active_storage/service/disk_service.rb 1980-01-02
01:00:00.000000000 +0100
@@ -60,7 +60,16 @@
def delete_prefixed(prefix)
instrument :delete_prefixed, prefix: prefix do
- Dir.glob(path_for("#{prefix}*")).each do |path|
+ prefix_path = path_for(prefix)
+
+ # File.expand_path (called within path_for) strips trailing slashes.
+ # Restore trailing separator if the original prefix had one, so that
+ # the glob "prefix/*" matches files inside the directory, not siblings
+ # whose names start with the prefix string.
+ prefix_path += "/" if prefix.end_with?("/")
+
+ escaped = escape_glob_metacharacters(prefix_path)
+ Dir.glob("#{escaped}*").each do |path|
FileUtils.rm_rf(path)
end
end
@@ -98,8 +107,39 @@
{ "Content-Type" => content_type }
end
+ # Every filesystem operation in DiskService resolves paths through this
method (or through
+ # make_path_for, which delegates here). This is the primary filesystem
security check: all
+ # path-traversal protection is enforced here. New methods that touch the
filesystem MUST use
+ # path_for or make_path_for -- never construct paths from +root+ directly.
def path_for(key) # :nodoc:
- File.join root, folder_for(key), key
+ if key.blank?
+ raise ActiveStorage::InvalidKeyError, "key is blank"
+ end
+
+ # Reject keys with dot segments as defense in depth. This prevents path
traversal both outside
+ # and within the storage root. The root containment check below is a
more fundamental check on
+ # path traversal outside of the disk service root.
+ begin
+ if key.split("/").intersect?(%w[. ..])
+ raise ActiveStorage::InvalidKeyError, "key has path traversal
segments"
+ end
+ rescue Encoding::CompatibilityError
+ raise ActiveStorage::InvalidKeyError, "key has incompatible encoding"
+ end
+
+ begin
+ path = File.expand_path(File.join(root, folder_for(key), key))
+ rescue ArgumentError
+ # ArgumentError catches null bytes
+ raise ActiveStorage::InvalidKeyError, "key is an invalid string"
+ end
+
+ # The resolved path must be inside the root directory.
+ unless path.start_with?(File.expand_path(root) + "/")
+ raise ActiveStorage::InvalidKeyError, "key is outside of disk service
root"
+ end
+
+ path
end
def compose(source_keys, destination_key, **)
@@ -156,6 +196,10 @@
[ key[0..1], key[2..3] ].join("/")
end
+ def escape_glob_metacharacters(path)
+ path.gsub(/[\[\]*?{}\\]/) { |c| "\\#{c}" }
+ end
+
def make_path_for(key)
path_for(key).tap { |path| FileUtils.mkdir_p File.dirname(path) }
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/active_storage.rb new/lib/active_storage.rb
--- old/lib/active_storage.rb 1980-01-02 01:00:00.000000000 +0100
+++ new/lib/active_storage.rb 1980-01-02 01:00:00.000000000 +0100
@@ -27,6 +27,7 @@
require "active_support"
require "active_support/rails"
require "active_support/core_ext/numeric/time"
+require "active_support/core_ext/numeric/bytes"
require "active_storage/version"
require "active_storage/deprecator"
@@ -350,6 +351,7 @@
]
mattr_accessor :unsupported_image_processing_arguments
+ mattr_accessor :streaming_chunk_max_size, default: 100.megabytes
mattr_accessor :service_urls_expire_in, default: 5.minutes
mattr_accessor :touch_attachment_records, default: true
mattr_accessor :urls_expire_in
@@ -360,6 +362,18 @@
mattr_accessor :track_variants, default: false
+ singleton_class.attr_accessor :checksum_implementation
+ @checksum_implementation = OpenSSL::Digest::MD5
+ begin
+ @checksum_implementation.hexdigest("test")
+ rescue # OpenSSL may have MD5 disabled
+ require "digest/md5"
+ @checksum_implementation = Digest::MD5
+ end
+
+ singleton_class.attr_accessor :streaming_max_ranges
+ @streaming_max_ranges = 1
+
mattr_accessor :video_preview_arguments, default: "-y -vframes 1 -f image2"
module Transformers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata 1980-01-02 01:00:00.000000000 +0100
+++ new/metadata 1980-01-02 01:00:00.000000000 +0100
@@ -1,7 +1,7 @@
--- !ruby/object:Gem::Specification
name: activestorage
version: !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
platform: ruby
authors:
- David Heinemeier Hansson
@@ -15,56 +15,56 @@
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
- !ruby/object:Gem::Dependency
name: actionpack
requirement: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
- !ruby/object:Gem::Dependency
name: activejob
requirement: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
- !ruby/object:Gem::Dependency
name: activerecord
requirement: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 8.0.3
+ version: 8.0.5
- !ruby/object:Gem::Dependency
name: marcel
requirement: !ruby/object:Gem::Requirement
@@ -189,10 +189,10 @@
- MIT
metadata:
bug_tracker_uri: https://github.com/rails/rails/issues
- changelog_uri:
https://github.com/rails/rails/blob/v8.0.3/activestorage/CHANGELOG.md
- documentation_uri: https://api.rubyonrails.org/v8.0.3/
+ changelog_uri:
https://github.com/rails/rails/blob/v8.0.5/activestorage/CHANGELOG.md
+ documentation_uri: https://api.rubyonrails.org/v8.0.5/
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
- source_code_uri: https://github.com/rails/rails/tree/v8.0.3/activestorage
+ source_code_uri: https://github.com/rails/rails/tree/v8.0.5/activestorage
rubygems_mfa_required: 'true'
rdoc_options: []
require_paths:
@@ -208,7 +208,7 @@
- !ruby/object:Gem::Version
version: '0'
requirements: []
-rubygems_version: 3.6.9
+rubygems_version: 4.0.6
specification_version: 4
summary: Local and cloud file storage framework.
test_files: []