Skip to content

feat(auth): Add blocking Regional Access Boundary Lookup and Seed Support#16720

Open
macastelaz wants to merge 18 commits intogoogleapis:mainfrom
macastelaz:clean-rab-gcloud
Open

feat(auth): Add blocking Regional Access Boundary Lookup and Seed Support#16720
macastelaz wants to merge 18 commits intogoogleapis:mainfrom
macastelaz:clean-rab-gcloud

Conversation

@macastelaz
Copy link
Copy Markdown

In order for the gcloud CLI to support Regional Access Boundary, the Python auth SDK needs to support blocking lookups as well as allowing an initial seed RAB to be provided (gcloud will set this seed if the CLI has a locally cached valid RAB available).

Additional details can be found at go/rab-python-gcloud-one-pager

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

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 renames the "Trust Boundary" feature to "Regional Access Boundary" (RAB) and introduces a centralized management system for it. Key changes include the implementation of _RegionalAccessBoundaryManager for thread-safe state handling and background refreshes, and the update of multiple credential types to support this new mechanism. The with_trust_boundary method is deprecated in favor of with_regional_access_boundary. Review feedback recommends updating a type hint in the utility module to correctly reflect the expected data types and removing redundant error logging in the base credentials class to reduce log noise.

Comment thread packages/google-auth/google/auth/_regional_access_boundary_utils.py Outdated
Comment thread packages/google-auth/google/auth/credentials.py
macastelaz and others added 5 commits April 23, 2026 19:14
Renamed 'with_regional_access_boundary' to '_with_regional_access_boundary' to indicate internal use.
Update the comment block of "_with_regional_access_boundary" to inform future maintainers of the necessity to maintain a backwards compatible contract of this method.
@macastelaz macastelaz changed the title Blocking Regional Access Boundary Lookup and Seed Support feat(auth): Add blocking Regional Access Boundary Lookup and Seed Support Apr 23, 2026
@macastelaz macastelaz marked this pull request as ready for review April 23, 2026 20:37
@macastelaz macastelaz requested review from a team as code owners April 23, 2026 20:37
Copy link
Copy Markdown
Contributor

@nbayati nbayati left a comment

Choose a reason for hiding this comment

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

Overall looks really good! Just a few small comments and questions.

Comment thread packages/google-auth/google/auth/credentials.py Outdated
Comment thread packages/google-auth/google/oauth2/credentials.py Outdated
Comment thread packages/google-auth/google/oauth2/credentials.py
Comment thread packages/google-auth/tests/oauth2/test__client.py
Comment thread packages/google-auth/tests/test__regional_access_boundary_utils.py
Comment thread packages/google-auth/google/auth/credentials.py
- Add test for token refresh and RAB lookup sequencing in before_request.
- Add failure test to verify blocking RAB lookups are not retried.
- Restore and refine test for skipping RAB lookup when URL is None.
- Fix swapped url/method arguments in before_request test calls.
- Document why OAuth2 credentials skip independent RAB lookups.
- Internalize blocking lookup method with leading underscore.
Comment thread packages/google-auth/tests/test__regional_access_boundary_utils.py
Copy link
Copy Markdown
Contributor

@nbayati nbayati left a comment

Choose a reason for hiding this comment

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

Great job!

@ohmayr ohmayr added the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Apr 27, 2026
@parthea parthea self-assigned this Apr 28, 2026
@daniel-sanche
Copy link
Copy Markdown
Contributor

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

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 introduces support for blocking regional access boundary (RAB) lookups and allows for seeding RAB data manually. Key changes include updates to the _RegionalAccessBoundaryManager to handle blocking refreshes, modifications to the Credentials class to support these new lookup modes, and adjustments to the OAuth2 client to implement configurable timeouts and retry logic for blocking requests. A critical issue was identified in the before_request implementation within the CredentialsWithRegionalAccessBoundary mixin, which currently relies on OAuth2-specific attributes and will cause failures for other credential types. Additionally, a docstring type hint for the seed parameter should be updated to Mapping[str, Any] to correctly reflect that the expiry key contains a datetime object.

Comment on lines +455 to +458
if self._use_non_blocking_refresh:
self._non_blocking_refresh(request)
else:
self._blocking_refresh(request)
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.

high

This implementation of before_request in the CredentialsWithRegionalAccessBoundary mixin is too specific to OAuth2 credentials. It relies on attributes like _use_non_blocking_refresh and methods like _non_blocking_refresh which are not present in the base Credentials class or other subclasses (e.g., ComputeEngineCredentials). This will cause an AttributeError when used with non-OAuth2 credentials.

Instead of duplicating the refresh logic, you should call super().before_request(). This allows the mixin to remain generic while still ensuring that the token is refreshed before the Regional Access Boundary lookup is triggered.

        super(CredentialsWithRegionalAccessBoundary, self).before_request(
            request, method, url, headers
        )

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.

This is worth confirming, but from my understanding, I'm not sure if this is an issue. CredentialsWithRegionalAccessBoundary inherits from Credentials, so it should have those internal attributes.

It does seem a little dangerous that before_request seems to be mostly copy/pasted from the superclass here though. I wonder if that can be cleaned up somehow? I could see these drifting over time

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.

Yes I think Gemini's assessment is incorrect. We had to duplicate the parent's logic here because we needed to ensure that the RAB lookup (which might be blocking) happens after the access token is refreshed but before headers are applied to the request. Credentials.before_request does both (refresh and apply) in one go.

I agree with the concern that they might drift over time. I think this can be refactored in the future and extract the common logic into a helper method. Would you be ok with us merging it as-is now, and doing the refactoring in the future?

Comment thread packages/google-auth/google/auth/_regional_access_boundary_utils.py Outdated
Copy link
Copy Markdown
Contributor

@daniel-sanche daniel-sanche left a comment

Choose a reason for hiding this comment

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

a bunch of small comments, and a few that are worth looking at closer. I know there's a bit of time pressure on this, so you can ignore some of the nits if needed


def use_blocking_regional_access_boundary_lookup(self):
"""Enables blocking regional access boundary lookup to true"""
self._use_blocking_regional_access_boundary_lookup = True
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.

I think this naming could get very confusing, since this is a state-changing function with an (almost) identical name to an internal data attribute. And the docstring isn't helpful

Can we change the function name to something like enable_blocking_lookup? And make the docstring explain what happens when this is enabled?

seed (Mapping[str, str]): The regional access boundary to use for the
credential. This should be a map with, at a minimum, an "encodedLocations"
key that maps to a hex string and an "expiry" key which maps to a
datetime.datetime.
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.

  • the docstring makes it sound like these fields required, but the code seems to work fine if they're not
  • why are we using a map for this? why not make encoded_locations and expiry arguments?

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.

Both are very valid. I made the fields arguments here, but kept the map for _with_regional_access_boundary(self, seed) since this is the method gcloud cli will be using.

Comment thread packages/google-auth/google/auth/_regional_access_boundary_utils.py Outdated
"""
Performs the Regional Access Boundary lookup and updates the state.
def start_blocking_refresh(self, credentials, request):
"""Initiates a blocking lookup of the Regional Access Boundary.
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.

nit: the docstring should probably mention what happens on an exception

Args:
request (google.auth.transport.Request): The object used to make
HTTP requests.
blocking (bool): Whether the lookup should be blocking.
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.

nit: more context would be helpful (e.g. "otherwise, the lookup will be preformed in a background thread", or something)

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.

The thread is spawned and managed by the caller (specifically by the _RegionalAccessBoundaryRefreshManager), and setting blocking here to true or false doesn't affect if it's run on the background or current thread.

class _RegionalAccessBoundaryRefreshThread(threading.Thread):
"""Thread for background refreshing of the Regional Access Boundary."""

def __init__(self, credentials, request, rab_manager):
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.

nit: typing could be helpful here. (Does this only work with CredentialsWithRegionalAccessBoundary credentials?)

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.

Yes, it only work with CredentialsWithRegionalAccessBoundary credential. I'm adding string literal type hints to avoid making a circular dependency.

Comment on lines +455 to +458
if self._use_non_blocking_refresh:
self._non_blocking_refresh(request)
else:
self._blocking_refresh(request)
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.

This is worth confirming, but from my understanding, I'm not sure if this is an issue. CredentialsWithRegionalAccessBoundary inherits from Credentials, so it should have those internal attributes.

It does seem a little dangerous that before_request seems to be mostly copy/pasted from the superclass here though. I wonder if that can be cleaned up somehow? I could see these drifting over time

url (str): The Regional Access Boundary lookup url.
can_retry (bool): Enable or disable request retry behavior. Defaults to true.
headers (Optional[Mapping[str, str]]): The headers for the request.
blocking (bool): Whether the lookup should be blocking.
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.

Doesn't it block in all cases here? It seems like "blocking" in this case just controls how timeout/retry configuration?

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.

I'm pretty confused by this, because it seems like it uses a much lower timeout and retry configuration when blocking is enabled, which is pretty much the opposite from what I would expect (1x 3 second attempt for blocking, vs 6x 120 second attempts for non-blocking)

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.

Thanks for pointing this out. I think the parameter name was a bit misleading.

The shorter timeout and no retry was an intentional choice because on gcloud has to use the blocking mode, which blocks the user's foreground action, and we want to fail fast (3s timeout, no retries) to avoid freezing the terminal for a long time if the endpoint is slow or down. The RAB fetching is a best effort operation, where we try to get the header to improve the call's routing and latency, but if it fails or is taking a long time, we'd want to let the call to go through without further delays.

I've renamed the parameter in the internal lookup methods from blocking to fail_fast to better describe the behavior, and updated the docstrings in credentials.py and _client.py to explicitly mention that fail_fast=True uses a short timeout and no retries.

Returns:
None: This credential type does not support RAB lookup.
"""
return None
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.

If this always returns None, it looks like this could result in a lot of failure logs here. In that context, None seems to represent a failure

Should this class overrride _is_regional_access_boundary_lookup_required to disable lookup? Or am I misunderstanding this?

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.

Great catch! Thank you for flagging this and the suggestion! I've added the overrride to _is_regional_access_boundary_lookup_required to return False. This ensures we don't attempt to call _build_regional_access_boundary_lookup_url, and would resolve the failures being logged.

Copy link
Copy Markdown
Contributor

@daniel-sanche daniel-sanche left a comment

Choose a reason for hiding this comment

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

LGTM

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

Labels

do not merge Indicates a pull request not ready for merge, due to either quality or timing.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants