Skip to content

fix: gracefully fallback if workload fields are missing from cert config#16022

Merged
daniel-sanche merged 4 commits intogoogleapis:mainfrom
nbayati:fix-mtls-fallback
Mar 4, 2026
Merged

fix: gracefully fallback if workload fields are missing from cert config#16022
daniel-sanche merged 4 commits intogoogleapis:mainfrom
nbayati:fix-mtls-fallback

Conversation

@nbayati
Copy link
Contributor

@nbayati nbayati commented Mar 4, 2026

Prevents exceptions during gECC flows or when falling back to SecureConnect by returning None instead of raising ClientCertError when X.509 workload fields are absent.

Prevents exceptions during gECC flows or when falling back to SecureConnect by returning None instead of raising ClientCertError when X.509 workload fields are absent.
@nbayati nbayati requested review from a team as code owners March 4, 2026 05:49
@gemini-code-assist
Copy link
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 refines the mTLS certificate configuration loading mechanism to be more resilient. Instead of immediately failing with an exception when expected X.509 workload fields are not found in the certificate configuration, the system will now return null values. This allows for a smoother transition to other mTLS authentication strategies, ensuring that incomplete configurations do not halt the authentication process prematurely.

Highlights

  • Graceful Fallback for mTLS Configuration: The _get_workload_cert_and_key_paths function in _mtls_helper.py now gracefully handles missing X.509 workload fields (like cert_configs, workload, cert_path, or key_path) by returning None, None instead of raising a ClientCertError.
  • Improved Error Handling: This change prevents exceptions during gECC flows or when falling back to other mTLS configurations like SecureConnect, allowing the system to attempt alternative authentication methods.
  • Test Updates: Corresponding unit tests were updated to reflect the new behavior, asserting that None is returned when workload fields are absent, rather than expecting an exception to be raised.
Changelog
  • packages/google-auth/google/auth/transport/_mtls_helper.py
    • Replaced raise exceptions.ClientCertError with return None, None for missing cert_configs in data.
    • Replaced raise exceptions.ClientCertError with return None, None for missing workload in cert_configs.
    • Replaced raise exceptions.ClientCertError with return None, None for missing cert_path in workload.
    • Replaced raise exceptions.ClientCertError with return None, None for missing key_path in workload.
  • packages/google-auth/tests/transport/test__mtls_helper.py
    • Updated test_no_cert_configs to assert None, None return instead of ClientCertError.
    • Updated test_no_workload to assert None, None return instead of ClientCertError.
    • Updated test_no_cert_file to assert None, None return instead of ClientCertError.
    • Updated test_no_key_file to assert None, None return instead of ClientCertError.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

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

Copy link
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 modifies _get_workload_cert_and_key_paths to return (None, None) instead of raising an exception when parts of the X.509 workload certificate configuration are missing. This makes the certificate handling more robust by allowing graceful fallbacks. The tests have been updated to reflect this new behavior. My review includes a suggestion to refactor the series of checks for missing keys into a more concise and Pythonic try...except block, which improves code maintainability.

Comment on lines 190 to 204
if "cert_configs" not in data:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "cert configs" object is expected'.format(
absolute_path
)
)
return None, None
cert_configs = data["cert_configs"]

if "workload" not in cert_configs:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "workload" cert config is expected'.format(
absolute_path
)
)
return None, None
workload = cert_configs["workload"]

if "cert_path" not in workload:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "cert_path" is expected in the workload cert config'.format(
absolute_path
)
)
return None, None
cert_path = workload["cert_path"]

if "key_path" not in workload:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "key_path" is expected in the workload cert config'.format(
absolute_path
)
)
return None, None
key_path = workload["key_path"]
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This series of if checks can be simplified by using a try...except KeyError block. This is a more idiomatic Python approach for this type of dictionary key validation, following the EAFP ('Easier to ask for forgiveness than permission') principle. This change would make the code more concise and readable.

Suggested change
if "cert_configs" not in data:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "cert configs" object is expected'.format(
absolute_path
)
)
return None, None
cert_configs = data["cert_configs"]
if "workload" not in cert_configs:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "workload" cert config is expected'.format(
absolute_path
)
)
return None, None
workload = cert_configs["workload"]
if "cert_path" not in workload:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "cert_path" is expected in the workload cert config'.format(
absolute_path
)
)
return None, None
cert_path = workload["cert_path"]
if "key_path" not in workload:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "key_path" is expected in the workload cert config'.format(
absolute_path
)
)
return None, None
key_path = workload["key_path"]
try:
workload = data["cert_configs"]["workload"]
cert_path = workload["cert_path"]
key_path = workload["key_path"]
except KeyError:
return None, None

Copy link
Contributor

@andyrzhao andyrzhao left a comment

Choose a reason for hiding this comment

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

LGTM overall. Left a minor comment.

Comment on lines 186 to -191
if "cert_configs" not in data:
raise exceptions.ClientCertError(
'Certificate config file {} is in an invalid format, a "cert configs" object is expected'.format(
absolute_path
)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

I would say that we can keep throwing an exception if "cert_configs" is missing as this field is a top-level requirement for the cert config spec. Thanks!

Copy link
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

@daniel-sanche daniel-sanche merged commit 3ed2d68 into googleapis:main Mar 4, 2026
27 checks passed
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.

3 participants