From d417f7fd9a3947085e5ab560540484e0b858431a Mon Sep 17 00:00:00 2001 From: Torrey Payne Date: Tue, 9 Jun 2026 22:42:35 +0000 Subject: [PATCH 1/3] fix(google-apis-core): upgrade addressable dependency to ~> 2.9 Upgrade addressable to ~> 2.9 to mitigate vulnerability GHSA-h27x-rffw-24p4. Fixes: https://github.com/googleapis/google-api-ruby-client/issues/26054 --- google-apis-core/google-apis-core.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-apis-core/google-apis-core.gemspec b/google-apis-core/google-apis-core.gemspec index 828f506410c..15648a8d71c 100644 --- a/google-apis-core/google-apis-core.gemspec +++ b/google-apis-core/google-apis-core.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |gem| gem.require_paths = ['lib'] gem.required_ruby_version = '>= 3.2' - gem.add_runtime_dependency 'addressable', '~> 2.8', '>= 2.8.7' + gem.add_runtime_dependency 'addressable', '~> 2.9' gem.add_runtime_dependency 'faraday', '~> 2.13' gem.add_runtime_dependency 'faraday-follow_redirects', '~> 0.3' gem.add_runtime_dependency 'googleauth', '~> 1.14' From 3c3beea3cd9e12e64e7907a16cb6b2e4d59cf1b8 Mon Sep 17 00:00:00 2001 From: Torrey Payne <11740989+torreypayne@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:51:31 +0000 Subject: [PATCH 2/3] fix(core): ignore non-2xx status codes in streaming downloads Prevents error response bodies (e.g. 503 Service Unavailable or 4xx error payloads) from being written into destination file streams during streaming downloads. Restores original pre-v1.0.0 allowlist filtering behavior (`!(200..299).include?(status)`) to prevent corrupted download offsets on retryable errors. Fixes googleapis/google-cloud-ruby#34750 --- .../lib/google/apis/core/download.rb | 5 +++-- .../lib/google/apis/core/storage_download.rb | 5 +++-- .../spec/google/apis/core/download_spec.rb | 17 +++++++++++++++++ .../google/apis/core/storage_download_spec.rb | 17 +++++++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/google-apis-core/lib/google/apis/core/download.rb b/google-apis-core/lib/google/apis/core/download.rb index 282ea15c905..1d2b77bd998 100644 --- a/google-apis-core/lib/google/apis/core/download.rb +++ b/google-apis-core/lib/google/apis/core/download.rb @@ -81,11 +81,12 @@ def execute_once(client, &block) http_res = client.get(url.to_s, query, request_header) do |request| request.options.on_data = proc do |chunk, _size, res| - # The on_data callback is only invoked on a successful response. # Some Faraday adapters (e.g. Typhoeus) may not provide a response # object in the callback, so we default to a 200 OK status. + # Note: Ignore non-2xx responses (redirects and 4xx/5xx error payloads) + # so error messages are not written to the download stream. status = res ? res.status.to_i : 200 - next if chunk.nil? || (status >= 300 && status < 400) + next if chunk.nil? || !(200..299).include?(status) # HTTP 206 is Partial Content download_offset ||= (status == 206 ? @offset : 0) diff --git a/google-apis-core/lib/google/apis/core/storage_download.rb b/google-apis-core/lib/google/apis/core/storage_download.rb index 476999c4073..709c6c68940 100644 --- a/google-apis-core/lib/google/apis/core/storage_download.rb +++ b/google-apis-core/lib/google/apis/core/storage_download.rb @@ -48,11 +48,12 @@ def execute_once(client, &block) http_res = client.get(url.to_s, query, request_header) do |request| request.options.on_data = proc do |chunk, _size, res| - # The on_data callback is only invoked on a successful response. # Some Faraday adapters (e.g. Typhoeus) may not provide a response # object in the callback, so we default to a 200 OK status. + # Note: Ignore non-2xx responses (redirects and 4xx/5xx error payloads) + # so error messages are not written to the download stream. status = res ? res.status.to_i : 200 - next if chunk.nil? || (status >= 300 && status < 400) + next if chunk.nil? || !(200..299).include?(status) download_offset ||= (status == 206 ? @offset : 0) download_offset += chunk.bytesize diff --git a/google-apis-core/spec/google/apis/core/download_spec.rb b/google-apis-core/spec/google/apis/core/download_spec.rb index dc8b5044146..85e22146e85 100644 --- a/google-apis-core/spec/google/apis/core/download_spec.rb +++ b/google-apis-core/spec/google/apis/core/download_spec.rb @@ -157,6 +157,23 @@ def write(data) end end + context 'when server responds with non-2xx status and error body' do + let(:dest) { StringIO.new } + + it 'does not write error body to destination IO' do + response = Faraday::Response.new(status: 503, body: 'Service Unavailable') + expect(client).to receive(:get) do |_url, _params, _headers, &block| + request = Faraday::Request.new + request.options = Faraday::RequestOptions.new + block.call(request) + request.options.on_data.call('Service Unavailable', 19, response) + response + end + expect { command.execute(client) }.to raise_error(Google::Apis::ServerError) + expect(dest.string).to be_empty + end + end + context 'with pathname destination' do let(:dest) { Pathname.new(File.join(Dir.mktmpdir, 'test-path.txt')) } let(:received) do diff --git a/google-apis-core/spec/google/apis/core/storage_download_spec.rb b/google-apis-core/spec/google/apis/core/storage_download_spec.rb index c60f17da16d..22fed8660cf 100644 --- a/google-apis-core/spec/google/apis/core/storage_download_spec.rb +++ b/google-apis-core/spec/google/apis/core/storage_download_spec.rb @@ -162,4 +162,21 @@ def write(data) expect(received).to eql 'Hello world' end end + + context 'when server responds with non-2xx status and error body' do + let(:dest) { StringIO.new } + + it 'does not write error body to destination IO' do + response = Faraday::Response.new(status: 503, body: 'Service Unavailable') + expect(client).to receive(:get) do |_url, _params, _headers, &block| + request = Faraday::Request.new + request.options = Faraday::RequestOptions.new + block.call(request) + request.options.on_data.call('Service Unavailable', 19, response) + response + end + expect { command.execute(client) }.to raise_error(Google::Apis::ServerError) + expect(dest.string).to be_empty + end + end end From 7c6ac96e6e38c9d1adc930b9d3b2267414d2c39c Mon Sep 17 00:00:00 2001 From: Torrey Payne <11740989+torreypayne@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:53:37 +0000 Subject: [PATCH 3/3] test(core): disable retries in non-2xx streaming unit tests --- google-apis-core/spec/google/apis/core/download_spec.rb | 1 + google-apis-core/spec/google/apis/core/storage_download_spec.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/google-apis-core/spec/google/apis/core/download_spec.rb b/google-apis-core/spec/google/apis/core/download_spec.rb index 85e22146e85..3bc9a170237 100644 --- a/google-apis-core/spec/google/apis/core/download_spec.rb +++ b/google-apis-core/spec/google/apis/core/download_spec.rb @@ -161,6 +161,7 @@ def write(data) let(:dest) { StringIO.new } it 'does not write error body to destination IO' do + command.options.retries = 0 response = Faraday::Response.new(status: 503, body: 'Service Unavailable') expect(client).to receive(:get) do |_url, _params, _headers, &block| request = Faraday::Request.new diff --git a/google-apis-core/spec/google/apis/core/storage_download_spec.rb b/google-apis-core/spec/google/apis/core/storage_download_spec.rb index 22fed8660cf..a135aec37c9 100644 --- a/google-apis-core/spec/google/apis/core/storage_download_spec.rb +++ b/google-apis-core/spec/google/apis/core/storage_download_spec.rb @@ -167,6 +167,7 @@ def write(data) let(:dest) { StringIO.new } it 'does not write error body to destination IO' do + command.options.retries = 0 response = Faraday::Response.new(status: 503, body: 'Service Unavailable') expect(client).to receive(:get) do |_url, _params, _headers, &block| request = Faraday::Request.new