Skip to content

Conversation

@gibfahn
Copy link

@gibfahn gibfahn commented Jan 8, 2026

Thank you for your interest in contributing! For general guidelines, please refer to
the contributing guide.

Please follow the guidelines below before opening an issue or a PR:

  • Ensure the issue was not already reported.
  • Create a new issue at https://github.com/GoogleContainerTools/jib/issues/new/choose if you are unable to find an existing issue addressing your problem. Make sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
  • Discuss the priority and potential solutions with the maintainers in the issue. The maintainers would review the issue and add a label "Accepting Contributions" once the issue is ready for accepting contributions.
  • Open a PR only if the issue is labeled with "Accepting Contributions", ensure the PR description clearly describes the problem and solution. Note that an open PR without an issues labeled with "Accepting Contributions" will not be accepted.
  • Verify that integration tests and unit tests are passing after the change.
  • Address all checkstyle issues. Refer to the style guide.

Jib may in some circumstances incorrectly determine that a repository
does not require authentication. Take for instance the case where
caching is used for the manifests or other components of a base image.
If the initial request succeeds then Jib assumes the repository does not
require authentication. In the case of a cache miss where authentication
is required, this may result in a 401 which is not handled and fails the
build. Jib should use the /v2/ endpoint to initially determine if the
repository requires authentication.

Fixes: #4385

Jib may in some circumstances incorrectly determine that a repository
does not require authentication. Take for instance the case where
caching is used for the manifests or other components of a base image.
If the initial request succeeds then Jib assumes the repository does not
require authentication. In the case of a cache miss where authentication
is required, this may result in a 401 which is not handled and fails the
build. Jib should use the /v2/ endpoint to initially determine if the
repository requires authentication.

Fixes: GoogleContainerTools#4385
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gibfahn, 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 resolves an issue where Jib could fail to authenticate with a container registry if an initial unauthenticated request succeeded (e.g., due to cached metadata), but subsequent operations (like downloading layers) required authentication. The core change introduces a flexible, on-demand authentication strategy. Instead of failing immediately on a 401 Unauthorized error, the system now attempts to dynamically re-authenticate the RegistryClient using a configurable exception handler, ensuring a more resilient build process when interacting with authenticated registries.

Highlights

  • On-Demand Authentication: Implemented a new mechanism to handle RegistryUnauthorizedException on demand, allowing the RegistryClient to re-authenticate dynamically when a 401 error occurs.
  • Refactored Base Image Pull: The PullBaseImageStep now uses an onDemandAuthRegistryClient and delegates 401 handling to a configurable RegistryUnauthorizedExceptionHandler.
  • New Exception Handling Interface: Introduced RegistryUnauthorizedExceptionHandler interface, providing a standardized way to customize how registry authentication failures are managed.
  • Enhanced Registry Client: The RegistryClient and its factory were updated to integrate and utilize the new RegistryUnauthorizedExceptionHandler for more flexible error handling.
  • Refined Credential Logging: Adjusted the logging behavior in RegistryCredentialRetriever to specifically log when no credentials are found for target images, while base image credential logging is now implicitly handled by the new authentication flow.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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 refactors the authentication handling for base image pulling to address caching issues, which could lead to incorrect assumptions about a repository's authentication requirements. The introduction of the RegistryUnauthorizedExceptionHandler interface is a solid design improvement, making the authentication logic more flexible and centralizing on-demand authentication. The changes effectively resolve the described issue and improve the robustness of the authentication flow. I have a couple of suggestions to improve code style by removing some unconventional brace patterns that affect readability.

Comment on lines +179 to 205
// Double indentation keeps code at same level as original code
{
{
final EventHandlers eventHandlers = registryClient.getEventHandlers();
final String imageReference = ex.getImageReference();
String wwwAuthenticate = ex.getHttpResponseException().getHeaders().getAuthenticate();
if (wwwAuthenticate != null) {
eventHandlers.dispatch(
LogEvent.debug("WWW-Authenticate for " + imageReference + ": " + wwwAuthenticate));
registryClient.authPullByWwwAuthenticate(wwwAuthenticate);
return new ImagesAndRegistryClient(
pullBaseImages(registryClient, progressDispatcher.newChildProducer()),
registryClient);

} else {
// Not getting WWW-Authenticate is unexpected in practice, and we may just blame the
// server and fail. However, to keep some old behavior, try a few things as a last resort.
// TODO: consider removing this fallback branch.
if (credential != null && !credential.isOAuth2RefreshToken()) {
eventHandlers.dispatch(
LogEvent.debug("Trying basic auth as fallback for " + imageReference + "..."));
registryClient.configureBasicAuth();
try {
return new ImagesAndRegistryClient(
pullBaseImages(registryClient, progressDispatcher.newChildProducer()),
registryClient);
} catch (RegistryUnauthorizedException ignored) {
// Fall back to try bearer auth.
}
}

eventHandlers.dispatch(
LogEvent.debug("Trying bearer auth as fallback for " + imageReference + "..."));
registryClient.doPullBearerAuth();
return new ImagesAndRegistryClient(
pullBaseImages(registryClient, progressDispatcher.newChildProducer()),
registryClient);
if (!registryClient.doPullBearerAuth()) {
eventHandlers.dispatch(
LogEvent.error("Failed to bearer auth for pull of " + imageReference));
throw ex;
}
}

// If another exception occurs, use the default behavior
return RegistryClient::defaultRegistryUnauthorizedExceptionHandler;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The use of double braces {{ ... }} and the accompanying comment is unconventional and harms code readability. While it might be intended to minimize diff noise, prioritizing long-term code clarity is generally better. Future maintainers could find this pattern confusing. I recommend removing the extra braces and the comment.

    final EventHandlers eventHandlers = registryClient.getEventHandlers();
    final String imageReference = ex.getImageReference();
    String wwwAuthenticate = ex.getHttpResponseException().getHeaders().getAuthenticate();
    if (wwwAuthenticate != null) {
      eventHandlers.dispatch(
          LogEvent.debug("WWW-Authenticate for " + imageReference + ": " + wwwAuthenticate));
      registryClient.authPullByWwwAuthenticate(wwwAuthenticate);
    } else {
      // Not getting WWW-Authenticate is unexpected in practice, and we may just blame the
      // server and fail. However, to keep some old behavior, try a few things as a last resort.
      // TODO: consider removing this fallback branch.
      eventHandlers.dispatch(
          LogEvent.debug("Trying bearer auth as fallback for " + imageReference + "..."));
      if (!registryClient.doPullBearerAuth()) {
        eventHandlers.dispatch(
            LogEvent.error("Failed to bearer auth for pull of " + imageReference));
        throw ex;
      }
    }

    // If another exception occurs, use the default behavior
    return RegistryClient::defaultRegistryUnauthorizedExceptionHandler;

Comment on lines +676 to 690
{
if (ex.getHttpResponseException().getStatusCode()
!= HttpStatusCodes.STATUS_CODE_UNAUTHORIZED
|| !isBearerAuth(authorization.get())
|| !isBearerAuth(registryClient.authorization.get())
|| ++bearerTokenRefreshes >= MAX_BEARER_TOKEN_REFRESH_TRIES) {
throw ex;
}

// Because we successfully did bearer authentication initially, getting 401 here probably
// means the token was expired.
String wwwAuthenticate = ex.getHttpResponseException().getHeaders().getAuthenticate();
authorization.set(refreshBearerAuth(wwwAuthenticate));
registryClient.authorization.set(registryClient.refreshBearerAuth(wwwAuthenticate));

return () -> this;
}
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 extra pair of braces is unnecessary and makes the code slightly harder to read. It's best to remove it for simplicity and to maintain a consistent coding style.

      if (ex.getHttpResponseException().getStatusCode()
              != HttpStatusCodes.STATUS_CODE_UNAUTHORIZED
          || !isBearerAuth(registryClient.authorization.get())
          || ++bearerTokenRefreshes >= MAX_BEARER_TOKEN_REFRESH_TRIES) {
        throw ex;
      }

      // Because we successfully did bearer authentication initially, getting 401 here probably
      // means the token was expired.
      String wwwAuthenticate = ex.getHttpResponseException().getHeaders().getAuthenticate();
      registryClient.authorization.set(registryClient.refreshBearerAuth(wwwAuthenticate));

      return () -> this;

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.

Jib authentication logic may not determine if authentication is required correctly

1 participant