Skip to content

Conversation

@bajajneha27
Copy link
Contributor

No description provided.

@product-auto-label product-auto-label bot added the api: storage Issues related to the Cloud Storage API. label Dec 23, 2025
@gemini-code-assist
Copy link

Summary of Changes

Hello @bajajneha27, 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 the storage client library by adding robust support for bucket encryption enforcement configurations. It introduces new data structures to represent Google Managed, Customer Managed, and Customer Supplied encryption restrictions, and integrates these into the core BucketEncryption model. The changes span across metadata handling, JSON serialization/deserialization, and gRPC communication, ensuring that these new encryption policies can be properly configured, retrieved, and updated for storage buckets.

Highlights

  • New Encryption Enforcement Configurations: Introduced three new C++ structs: GoogleManagedEncryptionEnforcementConfig, CustomerManagedEncryptionEnforcementConfig, and CustomerSuppliedEncryptionEnforcementConfig. These structs define restriction_mode and effective_time for different encryption types and include comparison and stream operators.
  • Extended BucketEncryption Struct: The existing BucketEncryption struct has been expanded to include instances of the newly defined encryption enforcement configuration structs, along with updated comparison and stream operators to reflect these additions.
  • Updated Metadata Parsing and Serialization: The internal parsing and serialization logic for BucketMetadata has been updated to correctly handle the new encryption enforcement configuration fields when converting to and from JSON, and when constructing patch requests.
  • gRPC Integration: The gRPC request parser and updater functions (PatchEncryption, UpdateEncryption) have been modified to map and handle the new encryption enforcement configuration fields between the client library's data structures and gRPC protocol buffers, including a new ToProtoTimestamp helper.
  • Comprehensive Unit Testing: A new unit test file (bucket_encryption_feature_test.cc) was added to validate the parsing, JSON serialization, and patching of the new bucket encryption enforcement configurations. Existing BucketMetadata and gRPC request parser tests were also updated.
  • Dependency Update: The googleapis-storage-testbench dependency was updated from v0.59.0 to v0.60.0 in the integration build script.

🧠 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

@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 adds support for bucket encryption enforcement configurations. The changes are well-structured and cover the necessary API, parsing, and testing aspects. However, I've identified several instances of code duplication that violate the repository's style guide, which prefers factoring out duplicated code that appears three or more times. I've also found a couple of issues in the tests that need to be addressed. My comments provide specific suggestions for refactoring the duplicated code and fixing the tests.

Comment on lines 112 to 121
"restriction_mode": "FULLY_RESTRICTED",
"effective_time": "2025-12-18T18:13:15Z"
},
"customerManagedEncryptionEnforcementConfig": {
"restriction_mode": "NOT_RESTRICTED",
"effective_time": "2025-12-18T18:13:15Z"
},
"customerSuppliedEncryptionEnforcementConfig": {
"restriction_mode": "NOT_RESTRICTED",
"effective_time": "2025-12-18T18:13:15Z"

Choose a reason for hiding this comment

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

high

The JSON keys for restriction_mode and effective_time should be in camelCase (restrictionMode, effectiveTime) to match the API specification and the parsing logic. The current snake_case keys will cause the parsing tests to fail or not test the intended functionality.

          "restrictionMode": "FULLY_RESTRICTED",
          "effectiveTime": "2025-12-18T18:13:15Z"
        },
        "customerManagedEncryptionEnforcementConfig": {
          "restrictionMode": "NOT_RESTRICTED",
          "effectiveTime": "2025-12-18T18:13:15Z"
        },
        "customerSuppliedEncryptionEnforcementConfig": {
          "restrictionMode": "NOT_RESTRICTED",
          "effectiveTime": "2025-12-18T18:13:15Z"

Comment on lines 516 to 520
nlohmann::json expected_encryption_enforcement_config{
{"googleManagedEncryptionEnforcementConfig", nlohmann::json{"restriction_mode", "FULLY_RESTRICTED"}},
{"customerManagedEncryptionEnforcementConfig", nlohmann::json{"restriction_mode", "NOT_RESTRICTED"}},
{"customerSuppliedEncryptionEnforcementConfig", nlohmann::json{"restriction_mode", "NOT_RESTRICTED"}}};
EXPECT_EQ(expected_encryption_enforcement_config, actual["encryption"]);

Choose a reason for hiding this comment

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

high

This test assertion is incorrect for several reasons:

  1. The expected_encryption_enforcement_config object is constructed incorrectly. nlohmann::json{"key", "value"} creates a JSON array ["key", "value"], not an object.
  2. The expected JSON is missing the defaultKmsKeyName and effectiveTime fields, which are present in the actual["encryption"] object.
  3. The JSON key is restriction_mode (snake_case), but it should be restrictionMode (camelCase).

Please check each field of actual["encryption"] individually instead of comparing against a partially constructed JSON object.

Comment on lines 35 to 81
struct GoogleManagedEncryptionEnforcementConfig {
std::string restriction_mode;
std::chrono::system_clock::time_point effective_time;
};

///@{
/// @name Comparison operators For GoogleManagedEncryptionEnforcementConfig
inline bool operator==(GoogleManagedEncryptionEnforcementConfig const& lhs,
GoogleManagedEncryptionEnforcementConfig const& rhs) {
return std::tie(lhs.restriction_mode, lhs.effective_time) ==
std::tie(rhs.restriction_mode, rhs.effective_time);
}

inline bool operator<(GoogleManagedEncryptionEnforcementConfig const& lhs,
GoogleManagedEncryptionEnforcementConfig const& rhs) {
return std::tie(lhs.restriction_mode, lhs.effective_time) <
std::tie(rhs.restriction_mode, rhs.effective_time);
}

inline bool operator!=(GoogleManagedEncryptionEnforcementConfig const& lhs,
GoogleManagedEncryptionEnforcementConfig const& rhs) {
return std::rel_ops::operator!=(lhs, rhs);
}

inline bool operator>(GoogleManagedEncryptionEnforcementConfig const& lhs,
GoogleManagedEncryptionEnforcementConfig const& rhs) {
return std::rel_ops::operator>(lhs, rhs);
}

inline bool operator<=(GoogleManagedEncryptionEnforcementConfig const& lhs,
GoogleManagedEncryptionEnforcementConfig const& rhs) {
return std::rel_ops::operator<=(lhs, rhs);
}

inline bool operator>=(GoogleManagedEncryptionEnforcementConfig const& lhs,
GoogleManagedEncryptionEnforcementConfig const& rhs) {
return std::rel_ops::operator>=(lhs, rhs);
}
///@}

inline std::ostream& operator<<(
std::ostream& os, GoogleManagedEncryptionEnforcementConfig const& rhs) {
return os << "GoogleManagedEncryptionEnforcementConfig={restriction_mode="
<< rhs.restriction_mode << ", effective_time="
<< google::cloud::internal::FormatRfc3339(rhs.effective_time)
<< "}";
}

Choose a reason for hiding this comment

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

medium

There is significant code duplication for the three ...EnforcementConfig structs. The struct definitions, comparison operators, and stream insertion operators are nearly identical for GoogleManagedEncryptionEnforcementConfig, CustomerManagedEncryptionEnforcementConfig, and CustomerSuppliedEncryptionEnforcementConfig. This could be refactored to reduce duplication and improve maintainability.

For example, you could use a template-based approach with tag dispatching to define the operators once for all three types, which would also help in maintaining type safety.

References
  1. The repository style guide prefers to factor out duplicated code if it appears 3 or more times in non-test files. The structs and their associated operators are duplicated three times here. (link)

Comment on lines 367 to 405
if (!v.google_managed_encryption_enforcement_config.restriction_mode
.empty()) {
builder.AddSubPatch(
"googleManagedEncryptionEnforcementConfig",
internal::PatchBuilder()
.SetStringField("restrictionMode",
v.google_managed_encryption_enforcement_config
.restriction_mode)
.SetStringField("effectiveTime",
google::cloud::internal::FormatRfc3339(
v.google_managed_encryption_enforcement_config
.effective_time)));
}
if (!v.customer_managed_encryption_enforcement_config.restriction_mode
.empty()) {
builder.AddSubPatch(
"customerManagedEncryptionEnforcementConfig",
internal::PatchBuilder()
.SetStringField("restrictionMode",
v.customer_managed_encryption_enforcement_config
.restriction_mode)
.SetStringField("effectiveTime",
google::cloud::internal::FormatRfc3339(
v.customer_managed_encryption_enforcement_config
.effective_time)));
}
if (!v.customer_supplied_encryption_enforcement_config.restriction_mode
.empty()) {
builder.AddSubPatch(
"customerSuppliedEncryptionEnforcementConfig",
internal::PatchBuilder()
.SetStringField("restrictionMode",
v.customer_supplied_encryption_enforcement_config
.restriction_mode)
.SetStringField("effectiveTime",
google::cloud::internal::FormatRfc3339(
v.customer_supplied_encryption_enforcement_config
.effective_time)));
}

Choose a reason for hiding this comment

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

medium

The logic for adding sub-patches for each encryption enforcement config is duplicated three times. This can be refactored into a helper function to reduce code duplication and improve readability.

  auto add_config_patch = [&](char const* name, auto const& config) {
    if (config.restriction_mode.empty()) return;
    builder.AddSubPatch(
        name,
        internal::PatchBuilder()
            .SetStringField("restrictionMode", config.restriction_mode)
            .SetStringField("effectiveTime",
                            google::cloud::internal::FormatRfc3339(
                                config.effective_time)));
  };
  add_config_patch("googleManagedEncryptionEnforcementConfig",
                   v.google_managed_encryption_enforcement_config);
  add_config_patch("customerManagedEncryptionEnforcementConfig",
                   v.customer_managed_encryption_enforcement_config);
  add_config_patch("customerSuppliedEncryptionEnforcementConfig",
                   v.customer_supplied_encryption_enforcement_config);
References
  1. The repository style guide prefers to factor out duplicated code if it appears 3 or more times in non-test files. The logic to build the patch for each encryption config is duplicated three times. (link)

Comment on lines 160 to 185
StatusOr<GoogleManagedEncryptionEnforcementConfig>
ParseGoogleManagedEncryptionEnforcementConfig(nlohmann::json const& json) {
auto restriction_mode = json.value("restrictionMode", "");
auto effective_time = internal::ParseTimestampField(json, "effectiveTime");
if (!effective_time) return std::move(effective_time).status();
return GoogleManagedEncryptionEnforcementConfig{std::move(restriction_mode),
*effective_time};
}

StatusOr<CustomerManagedEncryptionEnforcementConfig>
ParseCustomerManagedEncryptionEnforcementConfig(nlohmann::json const& json) {
auto restriction_mode = json.value("restrictionMode", "");
auto effective_time = internal::ParseTimestampField(json, "effectiveTime");
if (!effective_time) return std::move(effective_time).status();
return CustomerManagedEncryptionEnforcementConfig{std::move(restriction_mode),
*effective_time};
}

StatusOr<CustomerSuppliedEncryptionEnforcementConfig>
ParseCustomerSuppliedEncryptionEnforcementConfig(nlohmann::json const& json) {
auto restriction_mode = json.value("restrictionMode", "");
auto effective_time = internal::ParseTimestampField(json, "effectiveTime");
if (!effective_time) return std::move(effective_time).status();
return CustomerSuppliedEncryptionEnforcementConfig{
std::move(restriction_mode), *effective_time};
}

Choose a reason for hiding this comment

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

medium

The three Parse...Config functions are identical except for their return type. This duplication can be avoided by using a single template function.

template <typename ConfigType>
StatusOr<ConfigType> ParseEncryptionEnforcementConfig(
    nlohmann::json const& json) {
  auto restriction_mode = json.value("restrictionMode", "");
  auto effective_time = internal::ParseTimestampField(json, "effectiveTime");
  if (!effective_time) return std::move(effective_time).status();
  return ConfigType{std::move(restriction_mode), *effective_time};
}
References
  1. The repository style guide prefers to factor out duplicated code if it appears 3 or more times in non-test files. The parsing logic for each encryption config is duplicated three times. (link)

Comment on lines 425 to 451
auto const& gmek =
meta.encryption().google_managed_encryption_enforcement_config;
if (!gmek.restriction_mode.empty()) {
nlohmann::json config;
config["restrictionMode"] = gmek.restriction_mode;
config["effectiveTime"] =
google::cloud::internal::FormatRfc3339(gmek.effective_time);
e["googleManagedEncryptionEnforcementConfig"] = std::move(config);
}
auto const& cmek =
meta.encryption().customer_managed_encryption_enforcement_config;
if (!cmek.restriction_mode.empty()) {
nlohmann::json config;
config["restrictionMode"] = cmek.restriction_mode;
config["effectiveTime"] =
google::cloud::internal::FormatRfc3339(cmek.effective_time);
e["customerManagedEncryptionEnforcementConfig"] = std::move(config);
}
auto const& csek =
meta.encryption().customer_supplied_encryption_enforcement_config;
if (!csek.restriction_mode.empty()) {
nlohmann::json config;
config["restrictionMode"] = csek.restriction_mode;
config["effectiveTime"] =
google::cloud::internal::FormatRfc3339(csek.effective_time);
e["customerSuppliedEncryptionEnforcementConfig"] = std::move(config);
}

Choose a reason for hiding this comment

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

medium

The logic to serialize each of the three encryption enforcement configs to JSON is duplicated. This can be refactored into a helper function to reduce duplication and improve maintainability.

  auto to_json_config = [&](char const* name, auto const& config_source) {
    if (config_source.restriction_mode.empty()) return;
    nlohmann::json config;
    config["restrictionMode"] = config_source.restriction_mode;
    config["effectiveTime"] =
        google::cloud::internal::FormatRfc3339(config_source.effective_time);
    e[name] = std::move(config);
  };
  to_json_config("googleManagedEncryptionEnforcementConfig",
                 meta.encryption().google_managed_encryption_enforcement_config);
  to_json_config("customerManagedEncryptionEnforcementConfig",
                 meta.encryption().customer_managed_encryption_enforcement_config);
  to_json_config("customerSuppliedEncryptionEnforcementConfig",
                 meta.encryption().customer_supplied_encryption_enforcement_config);
References
  1. The repository style guide prefers to factor out duplicated code if it appears 3 or more times in non-test files. The serialization logic for each encryption config is duplicated three times. (link)

Comment on lines 336 to 359
auto const& gmek =
metadata.encryption().google_managed_encryption_enforcement_config;
if (!gmek.restriction_mode.empty()) {
auto& config =
*encryption.mutable_google_managed_encryption_enforcement_config();
config.set_restriction_mode(gmek.restriction_mode);
*config.mutable_effective_time() = ToProtoTimestamp(gmek.effective_time);
}
auto const& cmek =
metadata.encryption().customer_managed_encryption_enforcement_config;
if (!cmek.restriction_mode.empty()) {
auto& config =
*encryption.mutable_customer_managed_encryption_enforcement_config();
config.set_restriction_mode(cmek.restriction_mode);
*config.mutable_effective_time() = ToProtoTimestamp(cmek.effective_time);
}
auto const& csek =
metadata.encryption().customer_supplied_encryption_enforcement_config;
if (!csek.restriction_mode.empty()) {
auto& config =
*encryption.mutable_customer_supplied_encryption_enforcement_config();
config.set_restriction_mode(csek.restriction_mode);
*config.mutable_effective_time() = ToProtoTimestamp(csek.effective_time);
}

Choose a reason for hiding this comment

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

medium

The logic to update the proto for each of the three encryption enforcement configs is duplicated. This can be refactored into a helper lambda to reduce code duplication, similar to what was done in PatchEncryption.

  auto update_config = [&](auto const& source, auto* dest) {
    if (source.restriction_mode.empty()) return;
    dest->set_restriction_mode(source.restriction_mode);
    *dest->mutable_effective_time() = ToProtoTimestamp(source.effective_time);
  };

  update_config(metadata.encryption().google_managed_encryption_enforcement_config,
                encryption.mutable_google_managed_encryption_enforcement_config());
  update_config(metadata.encryption().customer_managed_encryption_enforcement_config,
                encryption.mutable_customer_managed_encryption_enforcement_config());
  update_config(metadata.encryption().customer_supplied_encryption_enforcement_config,
                encryption.mutable_customer_supplied_encryption_enforcement_config());
References
  1. The repository style guide prefers to factor out duplicated code if it appears 3 or more times in non-test files. The logic to update the proto for each encryption config is duplicated three times. (link)

@codecov
Copy link

codecov bot commented Dec 23, 2025

Codecov Report

❌ Patch coverage is 98.81657% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.96%. Comparing base (46f7e8b) to head (21d2f86).

Files with missing lines Patch % Lines
google/cloud/storage/bucket_encryption.h 95.83% 1 Missing ⚠️
...oud/storage/internal/grpc/bucket_request_parser.cc 97.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #15844      +/-   ##
==========================================
+ Coverage   92.94%   92.96%   +0.01%     
==========================================
  Files        2458     2458              
  Lines      227585   227742     +157     
==========================================
+ Hits       211531   211717     +186     
+ Misses      16054    16025      -29     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Labels

api: storage Issues related to the Cloud Storage API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant