Skip to content

fix(error_reporting): respect quota_project configuration#34610

Open
torreypayne wants to merge 9 commits into
mainfrom
fix-error-reporting-quota-project
Open

fix(error_reporting): respect quota_project configuration#34610
torreypayne wants to merge 9 commits into
mainfrom
fix-error-reporting-quota-project

Conversation

@torreypayne

@torreypayne torreypayne commented Jun 11, 2026

Copy link
Copy Markdown
Member

This PR fixes an issue where the Google::Cloud::ErrorReporting client was ignoring the quota_project configuration parameter, causing API calls to default billing to the project associated with the credentials. This resulted in PermissionDeniedError (Error Reporting API not enabled) for users attempting to report errors to a target project that was different from their credentials project (e.g. issue #25862).

closes: #25862

Changes

  • Updated Google::Cloud::ErrorReporting.new to resolve quota_project from the library configuration and pass it down to the internal Service layer.
  • Updated Google::Cloud::ErrorReporting::Service to accept quota_project and apply it to the underlying gRPC client configuration.
  • Documented quota_project usage in README.md and AUTHENTICATION.md.
  • Added unit tests to verify configuration propagation.

Expectation Setting on Project vs Quota Project

In Google Cloud APIs, the Target Project (where resources are stored/written) and the Quota Project (which project is billed for the API call) are intentionally separate concepts:

  • By default, the library bills the project associated with your credentials.
  • If you need to report errors to a project that differs from your credentials project, you must explicitly configure quota_project via library configuration or the GOOGLE_CLOUD_QUOTA_PROJECT environment variable.

How to configure:

Google::Cloud::ErrorReporting.configure do |config|
  config.project_id    = "target-project-id"   # Where errors are reported
  config.quota_project = "billing-project-id"  # Project billed for the quota (optional)
end
# Client will now respect the configured quota project for billing
client = Google::Cloud::ErrorReporting.new

=====

Manual testing logs:

irb(main):011> Google::Cloud::ErrorReporting.configure { |cfg| cfg.quota_project = 'global-billing-project' }
Key :pretty_print does not exist. Returning nil. at /usr/local/google/home/torreypayne/.gem/ruby/4.0.0/gems/pp-0.6.3/lib/pp.rb:212:in 'block (2 levels) in PP::PPMethods#pp'
=>
irb(main):012> er = Google::Cloud::ErrorReporting.new(project_id: "your-target-project")
=>
#<Google::Cloud::ErrorReporting::Project:0x00007f970b587d80
...
irb(main):013> # Verify it picked up the global configuration
irb(main):014> puts "Service Quota Project: #{er.service.quota_project}"
irb(main):015> puts "GRPC Quota Project: #{er.service.error_reporting.configure.quota_project}"
Service Quota Project: global-billing-project
GRPC Quota Project: global-billing-project
=> nil
irb(main):016> er = Google::Cloud::ErrorReporting.new(project_id: "your-target-project", quota_project: "your-billing-project")
=>
#<Google::Cloud::ErrorReporting::Project:0x00007f97083d6778
...
irb(main):017> # Verify it picked up the global configuration
irb(main):018> puts "Service Quota Project: #{er.service.quota_project}"
irb(main):019> puts "GRPC Quota Project: #{er.service.error_reporting.configure.quota_project}"
Service Quota Project: your-billing-project
GRPC Quota Project: your-billing-project
=> nil
irb(main):020> er = Google::Cloud::ErrorReporting.new(project_id: "your-target-project")
=>
#<Google::Cloud::ErrorReporting::Project:0x00007f9708442018
...
irb(main):021> # Verify it picked up the global configuration
irb(main):022> puts "Service Quota Project: #{er.service.quota_project}"
irb(main):023> puts "GRPC Quota Project: #{er.service.error_reporting.configure.quota_project}"
Service Quota Project: global-billing-project
GRPC Quota Project: global-billing-project

Torrey Payne added 2 commits June 11, 2026 18:10
Allows configuring quota_project explicitly in Google::Cloud::ErrorReporting.new
and via configuration. This resolves issues where the default quota project
from credentials is used but has the Error Reporting API disabled.
@torreypayne torreypayne marked this pull request as ready for review June 12, 2026 20:13
@torreypayne torreypayne requested review from a team and yoshi-approver as code owners June 12, 2026 20:13
@torreypayne torreypayne changed the title fix: support quota_project in ErrorReporting client fix(error_reporting): respect quota_project configuration Jun 15, 2026

@aandreassa aandreassa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! A couple nits

scope ||= configure.scope
timeout ||= configure.timeout
endpoint ||= configure.endpoint
quota_project = configure.quota_project

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move this line down and just use left alignment? It looks a bit off here since others are part of the parameter list.

@credentials = credentials
@timeout = timeout
@host = host
@quota_project = quota_project || (credentials.quota_project_id if credentials.respond_to? :quota_project_id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly more idiomatic to split the steps:

@quota_project = quota_project
@quota_project ||= credentials.quota_project_id if credentials.respond_to? :quota_project_id

doctest.before "Google::Cloud#error_reporting" do
mock_error_reporting do |mock|
mock.expect :report_error_event, nil, [Hash]
mock.expect :report_error_event, nil, [], project_name: Object, event: Object

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these be something else, such as String for project_name? You may be able to grab the specific type for event as well.

_(error_reporting).must_be_kind_of Google::Cloud::ErrorReporting::Project
end
end
Google::Cloud::ErrorReporting.configure.reset!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My hesitation here is this config not being isolated. I assume if the step above fails, then the config could leak into other tests. Should it have an after block instead like others?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The project_id option of Google::Cloud::ErrorReporting.new does not work

2 participants