Skip to content

Conversation

@diegomarquezp
Copy link
Contributor

  • feat(obs): generate gapic.properties file with repo property
  • feat: implement repo handling in gax
  • test: add tests for repo property
  • chore: speed up image building
  • build: introduce repo property to generation config
  • chore: update showcase module

@product-auto-label product-auto-label bot added the size: l Pull request size is large. label Feb 12, 2026
@diegomarquezp diegomarquezp added the wip Work in Progress label Feb 12, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @diegomarquezp, 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 significantly enhances observability for generated GAPIC clients by introducing a new gpc.client.repo span attribute. It establishes a mechanism for the GAPIC generator to embed repository information into a gapic.properties file, which is then consumed by the GAX library to enrich tracing spans. This change provides crucial context for identifying the source repository of client libraries during runtime, aiding in debugging and monitoring. The implementation includes updates across the GAPIC generator, GAX library, and associated build and test infrastructure.

Highlights

  • Observability Enhancement: Introduced a new gpc.client.repo span attribute to tracing, providing better context for generated GAPIC clients.
  • GAPIC Generator Modification: Modified the GAPIC generator to produce a gapic.properties file containing the repository information for generated libraries.
  • GAX Library Integration: Updated the GAX library to read the repo property from gapic.properties and include it in tracing contexts.
  • Build System Updates: Adjusted the build scripts and Dockerfile to pass the repo property during library generation and to optimize image building.
  • Comprehensive Testing: Added new unit and integration tests to ensure the correct parsing, generation, and usage of the repo property in both GAPIC generation and GAX tracing.
Changelog
  • .cloudbuild/library_generation/library_generation.Dockerfile
    • Added new Maven flags (-T 1.5C, -Denforcer.skip, -Dfmt.skip) to the mvn install command to speed up image building.
  • gapic-generator-java/src/main/java/com/google/api/generator/gapic/model/GapicContext.java
    • Added an abstract repo() method returning Optional<String> to the GapicContext class.
    • Initialized the repo field to Optional.empty() in the default builder.
  • gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java
    • Added parsing of the repo argument from the CodeGeneratorRequest.
    • Set the parsed repo option in the GapicContext builder.
  • gapic-generator-java/src/main/java/com/google/api/generator/gapic/protoparser/PluginArgumentParser.java
    • Defined KEY_REPO constant for the 'repo' plugin argument.
    • Implemented parseRepo method to extract the repo value from plugin arguments.
  • gapic-generator-java/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java
    • Added a call to writeGapicPropertiesFile within the main write method.
    • Implemented writeGapicPropertiesFile to create src/main/resources/gapic.properties with the repo value if present in GapicContext.
  • gapic-generator-java/src/test/java/com/google/api/generator/gapic/protoparser/PluginArgumentParserTest.java
    • Imported KEY_REPO for testing.
    • Added unit tests for parseRepo to verify correct parsing of the 'repo' argument and handling of its absence.
    • Added a helper method createRepo for test setup.
  • gapic-generator-java/src/test/java/com/google/api/generator/gapic/protowriter/WriterTest.java
    • Imported BufferedReader and Optional for new test cases.
    • Added a test writeRepoFile_isWritten to verify that gapic.properties is correctly generated with the repo value.
  • gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerContext.java
    • Imported necessary classes for Properties handling and logging.
    • Added LOGGER, GAPIC_PROPERTIES_FILE, and REPO_KEY constants.
    • Added an abstract getRepo() method to ApiTracerContext.
    • Modified newBuilder to load the repo property from gapic.properties if available.
    • Implemented loadRepoFromProperties to read the repo key from an InputStream and handle potential IOExceptions.
    • Added setRepo to the Builder class.
  • gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracer.java
    • Renamed LANGUAGE_ATTRIBUTE to REPO_ATTRIBUTE and introduced a new LANGUAGE_ATTRIBUTE for gcp.client.repo.
  • gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentricTracerFactory.java
    • Added logic to include the REPO_ATTRIBUTE in newAttemptAttributes if context.getRepo() is not null.
  • gax-java/gax/src/test/java/com/google/api/gax/tracing/ApiTracerContextTest.java
    • Added a new test file to verify the behavior of ApiTracerContext when loading the repo property from various input streams, including null, valid properties, missing keys, and IO errors.
  • gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerFactoryTest.java
    • Updated testWithContext_addsInferredAttributes to set a repo value in ApiTracerContext and assert its presence in attempt attributes.
    • Modified testWithContext_noEndpointContext_doesNotAddAttributes to use ApiTracerContext.newBuilder(null) and assert the absence of the REPO_ATTRIBUTE.
  • gax-java/gax/src/test/java/com/google/api/gax/tracing/AppCentricTracerTest.java
    • Imported assertThat and ArgumentCaptor for new test assertions.
    • Added testAttemptStarted_includesRepoAttribute to verify that the REPO_ATTRIBUTE is correctly included in attempt spans.
  • hermetic_build/library_generation/generate_composed_library.py
    • Passed generation_config and library objects to the __construct_effective_arg function.
    • Included the --repo argument in the generated protoc command using util.get_library_repository.
  • hermetic_build/library_generation/generate_library.sh
    • Added a --repo option to parse the repository argument.
    • Included a check to set a default repo if not provided.
    • Passed the repo variable as a new argument to the get_gapic_opts function.
  • hermetic_build/library_generation/tests/generate_library_unit_tests.sh
    • Added a repo variable to test functions.
    • Updated calls to get_gapic_opts to include the repo argument.
    • Modified assertEquals assertions to expect the repo parameter in the generated options string.
  • hermetic_build/library_generation/tests/utilities_unit_tests.py
    • Added new test methods (test_get_library_repository_with_common_protos_returns_sdk_platform_java, test_get_library_repository_with_monorepo_returns_google_cloud_java, test_get_library_repository_with_split_repo_returns_library_repo) to verify the get_library_repository function's logic.
  • hermetic_build/library_generation/utils/utilities.py
    • Introduced a new function get_library_repository to determine the correct repository string based on GenerationConfig and LibraryConfig (monorepo, common protos, or split repo).
    • Refactored generate_postprocessing_prerequisite_files to use the new get_library_repository function.
  • hermetic_build/library_generation/utils/utilities.sh
    • Added repo as a new parameter to the get_gapic_opts function.
    • Included the repo parameter in the echoed options string for protoc.
  • java-showcase/gapic-showcase/src/main/resources/gapic.properties
    • Added a new resource file gapic.properties with the content repo=googleapis/sdk-platform-java.
  • java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java
    • Defined SHOWCASE_REPO constant.
    • Added assertions in testTracing_successfulEcho_grpc and testTracing_successfulEcho_httpjson to verify that the gcp.client.repo attribute is present and correctly set in the tracing spans.
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 introduces a new gpc.client.repo span attribute for observability, propagating repository information from build configuration to tracing spans. However, a significant logic error exists where telemetry keys are swapped, leading to data corruption in audit logs. Furthermore, vulnerabilities related to insecure data handling (property injection and option injection) have been identified in the code processing repository information. There is also a high-severity bug in a build script and a medium-severity opportunity for code simplification using modern Java features.

Comment on lines +106 to +108
if [ -z "${repo}" ]; then
repo=$(repo)
fi
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The script attempts to call a repo command if the --repo argument is not provided. This command is not defined within the script or its sourced utilities, which will likely lead to a "command not found" error during execution. If the intention is to have a default value, it should be set explicitly. If no default is desired, it should probably default to an empty string to avoid an error.

Suggested change
if [ -z "${repo}" ]; then
repo=$(repo)
fi
if [ -z "${repo}" ]; then
repo=""
fi

Comment on lines 47 to 48
public static final String REPO_ATTRIBUTE = "gcp.client.language";
public static final String LANGUAGE_ATTRIBUTE = "gcp.client.repo";
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The constants REPO_ATTRIBUTE and LANGUAGE_ATTRIBUTE are swapped. REPO_ATTRIBUTE should be "gcp.client.repo" and LANGUAGE_ATTRIBUTE should be "gcp.client.language". This misconfiguration leads to incorrect telemetry data, where the repository name is reported as the language and vice-versa, corrupting audit logs and monitoring dashboards.

Suggested change
public static final String REPO_ATTRIBUTE = "gcp.client.language";
public static final String LANGUAGE_ATTRIBUTE = "gcp.client.repo";
public static final String REPO_ATTRIBUTE = "gcp.client.repo";
public static final String LANGUAGE_ATTRIBUTE = "gcp.client.language";

JarEntry jarEntry = new JarEntry("src/main/resources/gapic.properties");
try {
jos.putNextEntry(jarEntry);
jos.write(String.format("repo=%s\n", repo).getBytes(StandardCharsets.UTF_8));
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The writeGapicPropertiesFile method writes the repo string directly into a properties file using String.format("repo=%s\n", repo). If the repo string (which originates from user-supplied plugin arguments) contains a newline character, it can be used to inject arbitrary properties into the gapic.properties file. This could potentially influence the behavior of other components that read this configuration file.

Comment on lines +57 to +59
static Optional<String> parseRepo(CodeGeneratorRequest request) {
return parseConfigArgument(request.getParameter(), KEY_REPO);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The parseRepo method uses parseConfigArgument, which parses plugin arguments by splitting the input string by commas. If the repo value contains a comma, it will be split, potentially allowing an attacker to inject additional plugin flags or options (e.g., injecting ,metadata to enable metadata generation).

Comment on lines +73 to 90
private static void loadRepoFromProperties(Builder builder, @Nullable InputStream is) {
if (is == null) {
return;
}
try {
Properties properties = new Properties();
properties.load(is);
builder.setRepo(properties.getProperty(REPO_KEY));
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Could not load gapic.properties", e);
} finally {
try {
is.close();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Could not close gapic.properties stream", e);
}
}
}
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 loadRepoFromProperties method can be simplified by using a try-with-resources statement. This is the modern and recommended way to handle resources like InputStream in Java, as it ensures the stream is closed correctly and makes the code more concise and readable.

  private static void loadRepoFromProperties(Builder builder, @Nullable InputStream is) {
    if (is == null) {
      return;
    }
    try (InputStream inputStream = is) {
      Properties properties = new Properties();
      properties.load(inputStream);
      builder.setRepo(properties.getProperty(REPO_KEY));
    } catch (IOException e) {
      LOGGER.log(Level.WARNING, "Could not load or close gapic.properties", e);
    }
  }

@sonarqubecloud
Copy link

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed for 'java_showcase_integration_tests'

Failed conditions
68.2% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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

Labels

size: l Pull request size is large. wip Work in Progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant