Skip to content

fix(executor): skip x-goog-user-project header for OAuth auth method#870

Open
mateusmaaia wants to merge 8 commits into
googleworkspace:mainfrom
mateusmaaia:test-729-fix
Open

fix(executor): skip x-goog-user-project header for OAuth auth method#870
mateusmaaia wants to merge 8 commits into
googleworkspace:mainfrom
mateusmaaia:test-729-fix

Conversation

@mateusmaaia

Copy link
Copy Markdown

Summary

Re-opens the work from #863 (which itself picked up #827, both auto-closed by the stale-bot after 72 hours of inactivity — not rejected). #863 couldn't be reopened via the GitHub API/UI, so this is a fresh PR from the same branch (test-729-fix, now with one additional commit addressing review feedback).

Root cause (from #729/#827/#861): the CLI unconditionally sends the x-goog-user-project header (from project_id in client_secret.json) on every request. For OAuth desktop-app credentials, this triggers a GCP IAM check (serviceusage.services.use) that fails for any user who isn't an IAM member of the project backing the shared OAuth client — a common setup when an OAuth client is distributed org-wide. The API then returns a permission error that surfaces as 403 insufficientPermissions: Request had insufficient authentication scopes even though the token's actual scopes are correct. Confirmed to affect Drive, admin-reports, and calendar.events.list.

Fix

  • ServiceAccount: always forward the quota project (env var, config, or ADC) — service accounts need it and are project members by construction.
  • OAuth: only send x-goog-user-project when GOOGLE_WORKSPACE_PROJECT_ID is explicitly set (opt-in) — otherwise omit it entirely, since OAuth users may not be IAM members of the client's backing project.
  • None: never send it.

On top of #863's commits, this adds:

  • Replaced the local QUOTA_PROJECT_ENV_MUTEX in the executor tests with #[serial_test::serial] (the pattern already used elsewhere in this crate for tests that mutate GOOGLE_WORKSPACE_PROJECT_ID), per gemini-code-assist's outstanding review comment on fix(executor): skip x-goog-user-project header for OAuth auth method #863. The two test fns are gated with #[cfg(test)] so plain cargo clippy --workspace (no --tests) doesn't try to link the serial_test dev-dependency.

Verification

  • cargo test -p google-workspace-cli: 701 passed, 2 failed (pre-existing ADC-path test failures unrelated to this change — reproduced independently on a clean origin/main checkout).
  • cargo fmt --all -- --check: clean.
  • cargo clippy --workspace -- -D warnings: clean, except one pre-existing, unrelated collapsible_match warning in helpers/script.rs that also reproduces on a fresh origin/main checkout without this branch.
  • Branch is a clean fast-forward on top of current origin/main.

Fixes #729
Fixes #861
Related to the admin-reports case reported in #729
Supersedes #863

Co-authored-by: Varun Nuthalapati nuthalapativarun@gmail.com

nuthalapativarun and others added 6 commits May 31, 2026 20:15
…ta header

AuthMethod::OAuth covers both user OAuth and service-account credentials,
so the previous check (*auth_method != AuthMethod::OAuth) would incorrectly
suppress the x-goog-user-project header for service accounts (which do need
it) while also setting it on unauthenticated (None) requests.

Add AuthMethod::ServiceAccount and auth::CredentialKind so the call site in
main.rs can tag the request with the right variant. The quota header is now
only sent for ServiceAccount auth; user OAuth requests remain header-free to
avoid 403 errors for users who are not IAM members of the project.
Replace the separate CredentialKind enum with the existing AuthMethod
enum (moved from executor.rs to auth.rs so authentication types live
with authentication code).  get_token_with_kind now returns AuthMethod
directly, eliminating the mapping boilerplate in main.rs.

Resolves Gemini r2 comment on PR googleworkspace#827.
…icitly set

The previous fix completely omitted x-goog-user-project for OAuth, which
broke the documented GOOGLE_WORKSPACE_PROJECT_ID env var behaviour. Users
who explicitly set that variable expect the header to be forwarded.

New behaviour:
- ServiceAccount: always send the header (env var, config, or ADC)
- OAuth: only send when GOOGLE_WORKSPACE_PROJECT_ID is explicitly set
- None: never send

Also serialise the two env-var-mutating tests with a static Mutex to
avoid races when the test binary runs threads in parallel.
- QUOTA_PROJECT_ENV_MUTEX is only referenced from #[tokio::test]
  functions, which aren't compiled outside test builds, so plain
  `cargo clippy --workspace` (CI's lint job) flagged it as dead code.
- cargo fmt line-wrap on the new test's assert_eq! chain.
…w feedback

Replaces the local QUOTA_PROJECT_ENV_MUTEX with the #[serial_test::serial]
attribute already used elsewhere in this crate for serialising tests that
mutate GOOGLE_WORKSPACE_PROJECT_ID, per gemini-code-assist's review comment
on PR googleworkspace#827/googleworkspace#863. The two test fns are gated with #[cfg(test)] so plain
`cargo clippy --workspace` (which doesn't set cfg(test)) doesn't try to
link the serial_test dev-dependency.
@changeset-bot

changeset-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a8b854d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@googleworkspace-bot googleworkspace-bot added area: auth area: http area: core Core CLI parsing, commands, error handling, utilities labels Jul 7, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where the CLI's unconditional inclusion of the 'x-goog-user-project' header caused authentication failures for OAuth users. By making this header optional for OAuth users—unless explicitly opted into via 'GOOGLE_WORKSPACE_PROJECT_ID'—the changes ensure better compatibility with shared OAuth clients while maintaining necessary quota attribution for service accounts.

Highlights

  • OAuth Header Handling: Modified the executor to conditionally omit the 'x-goog-user-project' header for OAuth requests, preventing 403 insufficientPermissions errors for users who are not IAM members of the client's backing project.
  • Authentication Method Tracking: Introduced an 'AuthMethod' enum and updated the token retrieval flow to accurately track and propagate the authentication type (OAuth, ServiceAccount, or None) throughout the request execution.
  • Testing Improvements: Added unit tests to verify header behavior for OAuth requests and utilized 'serial_test' to safely handle environment variable mutations during testing.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request skips the x-goog-user-project header for OAuth authentication by default to prevent 403 errors for non-project-member users, while still forwarding it for service accounts or when explicitly requested via the GOOGLE_WORKSPACE_PROJECT_ID environment variable. The feedback suggests refactoring get_token to call the new get_token_with_kind function to eliminate code duplication, and using an RAII guard in the unit tests to prevent environment variable pollution in case of test panics.

Comment thread crates/google-workspace-cli/src/auth.rs
Comment thread crates/google-workspace-cli/src/executor.rs
…var test cleanup

- get_token now delegates to get_token_with_kind and discards the
  AuthMethod, removing the near-duplicate credential-loading logic
  between the two functions (gemini-code-assist review on googleworkspace#870).
- The two executor tests that mutate GOOGLE_WORKSPACE_PROJECT_ID now use
  an RAII EnvVarGuard (mirroring auth.rs's test helper) so the env var is
  restored even if an assertion panics mid-test.
@googleworkspace-bot

Copy link
Copy Markdown
Collaborator

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request aims to prevent 403 errors for non-project-member users by skipping the x-goog-user-project header during OAuth authentication, unless the GOOGLE_WORKSPACE_PROJECT_ID environment variable is explicitly set. It introduces an AuthMethod enum to track the authentication type and updates token retrieval and request building logic accordingly. The review feedback highlights a potential issue where service accounts might incorrectly use the OAuth client's project ID from client_secret.json as the quota project, which can also lead to 403 errors. The reviewer suggests introducing a helper function get_quota_project_for_method to properly resolve the quota project based on the authentication method.

Comment thread crates/google-workspace-cli/src/auth.rs
Comment thread crates/google-workspace-cli/src/executor.rs Outdated
…or service accounts

get_quota_project() previously fell back to project_id from the OAuth
client configuration (client_secret.json) for service-account requests.
That project isn't necessarily one the service account is an IAM member
of, so forwarding it as x-goog-user-project reintroduces the same class
of 403 insufficientPermissions error this PR fixes for OAuth.

Replaces get_quota_project() with get_quota_project_for_method(AuthMethod),
which only consults GOOGLE_WORKSPACE_PROJECT_ID or ADC's quota_project_id
for service accounts, and never the OAuth client config. executor.rs now
calls this single helper instead of duplicating the OAuth/ServiceAccount
branching inline (gemini-code-assist review on googleworkspace#870).
@googleworkspace-bot

Copy link
Copy Markdown
Collaborator

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request modifies the CLI to conditionally set the x-goog-user-project header based on the authentication method used, preventing 403 errors for OAuth users who are not IAM members of the project. It introduces an AuthMethod enum, refactors token retrieval to return the authentication method, and updates the quota project resolution logic and request builder accordingly. Extensive unit tests have been added to verify the new behavior. There are no review comments to address, so I have no additional feedback to provide.

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

Labels

area: auth area: core Core CLI parsing, commands, error handling, utilities area: http

Projects

None yet

3 participants