-
Notifications
You must be signed in to change notification settings - Fork 346
fix: detect correct auth when ADC env var is set but empty #1374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: detect correct auth when ADC env var is set but empty #1374
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
chalmerlowe
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
|
||
| cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() | ||
| explicit_file = os.environ.get(environment_vars.CREDENTIALS) | ||
| explicit_file = os.environ.get(environment_vars.CREDENTIALS, "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I like using "" to represent the empty state. That seems like it could lead to confusing situations down the line. Instead, I'd recommend:
- changing this line to
os.environ.get(environment_vars.CREDENTIALS) or None, which will replace empty strings withNone
or
- use
if explicit_file:in place of the checks, which will respond to None and empty strings the same way, since both are falsy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Daniel:
Thanks for this comment. I considered similar ideas when evaluating this, and this is the conclusion I came to:
The variable explicit_file is a local variable within _get_explicit_environ_credentials(), so no external API is changed or affected and the way the code is currently written, it must be a str. Why? Because of the default behavior of the .get() method on a dict and because of the return object from .get_application_default_credentials_path() which is a str.
dict .get()
Environmental variables are stored as strings AND if the CREDENTIALS variable is not found, we return an empty string as the default value. There is no reason to return a None, it serves no additional purpose in the limited uses that we have for the variable explicit_file.
explicit_file = os.environ.get(environment_vars.CREDENTIALS, "")
_cloud_sdk.get_application_default_credentials_path()
This function returns a string.
def get_application_default_credentials_path():
"""Gets the path to the application default credentials file.
The path may or may not exist.
Returns:
str: The full path to application default credentials.
"""
In the comparision, we are checking to see IF explicit_file was unset AND if not, whether the path matches the path referenced by cloud_sdk_adc_path. There is no need OR reason to prefer None over the empty string.
if explicit_file != "" and explicit_file == cloud_sdk_adc_path:
So why use the empty string?
Old Behavior: Defaulted to None if unset.
New Behavior: Defaults to "" if unset (via os.environ.get(..., "")).
Result: The logic now treats "unset" and "set to empty string" identically (as ""). The check explicit_file != "" correctly handles both cases (unset OR empty string) by skipping the file load, which prevents a crash. cloud_sdk_adc_path always returns a string path, so the comparison remains safe.
Before I had fully worked through the above logic, I had considered something such as:
if explicit_file not in {None, ""} and feel that while if explicit_file not in {None, ""} OR similar patterns (such as you recommend) where we look for both is a valid defensive pattern, the current PR's approach is slightly cleaner because it enforces type consistency. If we initialize explicit_file with a default of "", the variable is always a str, avoiding mixed types (Optional[str]). The current implementation explicit_file != "" is correct given the initialization change.
daniel-sanche
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider my comment, but I think this is also ok to merge as-is
Treat empty strings as if the env var was not set. This fixes an issue where an environment variable for
GOOGLE_APPLICATION_CREDENTIALSis set, but it empty. Because the default sentinel isNone, the auth library attempts to load this file. Some systems can set or update an env var, but not unset an env var (e.g. Docker).Fixes: googleapis/python-pubsub#983