Skip to content

Commit ff539bf

Browse files
committed
feat(storage): add support for bucket encryption enforcement config
1 parent 46f7e8b commit ff539bf

File tree

4 files changed

+79
-4
lines changed

4 files changed

+79
-4
lines changed

google/cloud/storage/bucket_encryption.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,31 @@ namespace cloud {
2323
namespace storage {
2424
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2525

26+
/**
27+
* Google Managed Encryption (GMEK) enforcement config of a bucket.
28+
*/
29+
struct GoogleManagedEncryptionEnforcementConfig {
30+
std::string restriction_mode;
31+
std::chrono::system_clock::time_point effective_time;
32+
};
33+
34+
inline bool operator==(GoogleManagedEncryptionEnforcementConfig const& lhs,
35+
GoogleManagedEncryptionEnforcementConfig const& rhs) {
36+
return std::tie(lhs.restriction_mode, lhs.effective_time) ==
37+
std::tie(rhs.restriction_mode, rhs.effective_time);
38+
}
39+
40+
inline bool operator<(GoogleManagedEncryptionEnforcementConfig const& lhs,
41+
GoogleManagedEncryptionEnforcementConfig const& rhs) {
42+
return std::tie(lhs.restriction_mode, lhs.effective_time) <
43+
std::tie(rhs.restriction_mode, rhs.effective_time);
44+
}
45+
46+
inline bool operator!=(GoogleManagedEncryptionEnforcementConfig const& lhs,
47+
GoogleManagedEncryptionEnforcementConfig const& rhs) {
48+
49+
}
50+
2651
/**
2752
* Describes the default customer managed encryption key for a bucket.
2853
*
@@ -37,6 +62,9 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
3762
*/
3863
struct BucketEncryption {
3964
std::string default_kms_key_name;
65+
GoogleManagedEncryptionEnforcementConfig google_managed_encryption_enforcement_config;
66+
CustomerManagedEncryptionEnforcementConfig customer_managed_encryption_enforcement_config;
67+
CustomerSuppliedEncryptionEnforcementConfig customer_supplied_encryption_enforcement_config;
4068
};
4169

4270
inline bool operator==(BucketEncryption const& lhs,

google/cloud/storage/bucket_metadata.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ std::ostream& operator<<(std::ostream& os, BucketMetadata const& rhs) {
150150
os << "]";
151151

152152
if (rhs.has_encryption()) {
153-
os << ", encryption.default_kms_key_name="
154-
<< rhs.encryption().default_kms_key_name;
153+
os << ", encryption="
154+
<< rhs.encryption();
155155
}
156156

157157
os << ", etag=" << rhs.etag();

google/cloud/storage/bucket_metadata_test.cc

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,19 @@ BucketMetadata CreateBucketMetadataForTest() {
107107
"etag": "AYX="
108108
}],
109109
"encryption": {
110-
"defaultKmsKeyName": "projects/test-project-name/locations/us-central1/keyRings/test-keyring-name/cryptoKeys/test-key-name"
110+
"defaultKmsKeyName": "projects/test-project-name/locations/us-central1/keyRings/test-keyring-name/cryptoKeys/test-key-name",
111+
"googleManagedEncryptionEnforcementConfig": {
112+
"restriction_mode": "FULLY_RESTRICTED",
113+
"effective_time": "2025-12-18T18:13:15Z"
114+
},
115+
"customerManagedEncryptionEnforcementConfig": {
116+
"restriction_mode": "NOT_RESTRICTED",
117+
"effective_time": "2025-12-18T18:13:15Z"
118+
},
119+
"customerSuppliedEncryptionEnforcementConfig": {
120+
"restriction_mode": "NOT_RESTRICTED",
121+
"effective_time": "2025-12-18T18:13:15Z"
122+
}
111123
},
112124
"etag": "XYZ=",
113125
"hierarchicalNamespace": {
@@ -224,6 +236,10 @@ TEST(BucketMetadataTest, Parse) {
224236
"projects/test-project-name/locations/us-central1/keyRings/"
225237
"test-keyring-name/cryptoKeys/test-key-name",
226238
actual.encryption().default_kms_key_name);
239+
EXPECT_EQ("FULLY_RESTRICTED", actual.encryption().googleManagedEncryptionEnforcementConfig.restriction_mode);
240+
EXPECT_EQ("NOT_RESTRICTED", actual.encryption().customerManagedEncryptionEnforcementConfig.restriction_mode);
241+
EXPECT_EQ("NOT_RESTRICTED", actual.encryption().customerSuppliedEncryptionEnforcementConfig.restriction_mode);
242+
EXPECT_EQ("2025-12-18T18:13:15Z", actual.encryption().customerSuppliedEncryptionEnforcementConfig.effective_time);
227243
EXPECT_EQ("XYZ=", actual.etag());
228244
// hierarchicalNamespace
229245
ASSERT_TRUE(actual.has_hierarchical_namespace());
@@ -493,6 +509,11 @@ TEST(BucketMetadataTest, ToJsonString) {
493509
"projects/test-project-name/locations/us-central1/keyRings/"
494510
"test-keyring-name/cryptoKeys/test-key-name",
495511
actual["encryption"].value("defaultKmsKeyName", ""));
512+
nlohmann::json expected_encryption_enforcement_config{
513+
{"googleManagedEncryptionEnforcementConfig", nlohmann::json{"restriction_mode", "FULLY_RESTRICTED"}},
514+
{"customerManagedEncryptionEnforcementConfig", nlohmann::json{"restriction_mode", "NOT_RESTRICTED"}},
515+
{"customerSuppliedEncryptionEnforcementConfig", nlohmann::json{"restriction_mode", "NOT_RESTRICTED"}}};
516+
EXPECT_EQ(expected_encryption_enforcement_config, actual["encryption"]);
496517

497518
// hierarchical_namespace()
498519
ASSERT_EQ(1, actual.count("hierarchicalNamespace"));
@@ -849,8 +870,13 @@ TEST(BucketMetadataTest, SetEncryption) {
849870
std::string fake_key_name =
850871
"projects/test-project-name/locations/us-central1/keyRings/"
851872
"test-keyring-name/cryptoKeys/another-test-key-name";
852-
copy.set_encryption(BucketEncryption{fake_key_name});
873+
std::string fake_restriction_mode = "FULLY_RESTRICTED";
874+
875+
copy.set_encryption(BucketEncryption{fake_key_name, fake_restriction_mode});
853876
EXPECT_EQ(fake_key_name, copy.encryption().default_kms_key_name);
877+
EXPECT_EQ(fake_restriction_mode, copy.encryption().googleManagedEncryptionEnforcementConfig.restriction_mode);
878+
EXPECT_EQ(fake_restriction_mode, copy.encryption().customerManagedEncryptionEnforcementConfig.restriction_mode);
879+
EXPECT_EQ(fake_restriction_mode, copy.encryption().customerSuppliedEncryptionEnforcementConfig.restriction_mode);
854880
EXPECT_NE(expected, copy);
855881
}
856882

google/cloud/storage/internal/bucket_metadata_parser.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,32 @@ Status ParseEncryption(BucketMetadata& meta, nlohmann::json const& json) {
160160
if (json.contains("encryption")) {
161161
BucketEncryption e;
162162
e.default_kms_key_name = json["encryption"].value("defaultKmsKeyName", "");
163+
e.google_managed_encryption_enforcement_config = ParseGoogleManagedEncryptionEnforcementConfig(json["encryption"]);
164+
e.customer_managed_encryption_enforcement_config = ParseCustomerManagedEncryptionEnforcementConfig(json["encryption"]);
165+
e.customer_supplied_encryption_enforcement_config = ParseCustomerSuppliedEncryptionEnforcementConfig(json["encryption"]);
163166
meta.set_encryption(std::move(e));
164167
}
165168
return Status{};
166169
}
167170

171+
StatusOr<GoogleManagedEncryptionEnforcementConfig> ParseGoogleManagedEncryptionEnforcementConfig(nlohmann::json const& json) {
172+
auto restriction_mode = json["restriction_mode"];
173+
auto effective_time = internal::ParseTimestampField(json, "effective_time");
174+
return GoogleManagedEncryptionEnforcementConfig{*restriction_mode, *effective_time};
175+
}
176+
177+
StatusOr<CustomerManagedEncryptionEnforcementConfig> ParseCustomerManagedEncryptionEnforcementConfig(nlohmann::json const& json) {
178+
auto restriction_mode = json["restriction_mode"];
179+
auto effective_time = internal::ParseTimestampField(json, "effective_time");
180+
return CustomerManagedEncryptionEnforcementConfig{*restriction_mode, *effective_time};
181+
}
182+
183+
StatusOr<CustomerSuppliedEncryptionEnforcementConfig> ParseCustomerSuppliedEncryptionEnforcementConfig(nlohmann:json const& json) {
184+
auto restriction_mode = json["restriction_mode"];
185+
auto effective_time = internal::ParseTimestampField(json, "effective_time");
186+
return CustomerSuppliedEncryptionEnforcementConfig{*restriction_mode, *effective_time};
187+
}
188+
168189
Status ParseHierarchicalNamespace(BucketMetadata& meta,
169190
nlohmann::json const& json) {
170191
auto const i = json.find("hierarchicalNamespace");

0 commit comments

Comments
 (0)