From e337c21551b685e42b0c8d3f9fffa2fe672a0b01 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Wed, 21 Jan 2026 10:58:27 +0530 Subject: [PATCH 01/11] Adding code samples for creating secret with customer managed encryption key and deleting annotations from the secret --- secretmanager/README.md | 4 +- .../secretmanager/CreateSecretWithCmek.java | 76 ++++++++++++++++ .../DeleteSecretAnnotations.java | 77 ++++++++++++++++ .../CreateRegionalSecretWithCmek.java | 75 ++++++++++++++++ .../DeleteRegionalSecretAnnotations.java | 88 +++++++++++++++++++ .../test/java/secretmanager/SnippetsIT.java | 28 +++++- .../regionalsamples/SnippetsIT.java | 29 ++++++ 7 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java create mode 100644 secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java diff --git a/secretmanager/README.md b/secretmanager/README.md index 0af70bfd6bf..0ffcc0d9ec0 100644 --- a/secretmanager/README.md +++ b/secretmanager/README.md @@ -16,10 +16,12 @@ You must [enable the Secret Manager API](https://console.cloud.google.com/flows/ ### Set Environment Variables -You must set your project ID in order to run the tests +You must set your project ID, KMS Keys (Global and Regional) in order to run the tests ```text $ export GOOGLE_CLOUD_PROJECT= +$ export GOOGLE_CLOUD_REGIONAL_KMS_KEY= (region same as location) +$ export GOOGLE_CLOUD_KMS_KEY= ``` ### Grant Permissions diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java new file mode 100644 index 00000000000..b185047a2e0 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java @@ -0,0 +1,76 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_create_secret_with_annotations] +import com.google.cloud.secretmanager.v1.CustomerManagedEncryption; +import com.google.cloud.secretmanager.v1.ProjectName; +import com.google.cloud.secretmanager.v1.Replication; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import java.io.IOException; + +public class CreateSecretWithCmek { + + public static void main() throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + // This is the Full kms key name to be used for Cmek. + String kmsKeyName = "your-kms-key-name"; + createSecretWithCmek(projectId, secretId, kmsKeyName); + } + + // Create a secret with annotations. + public static Secret createSecretWithCmek(String projectId, String secretId, String kmsKeyName) + throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + + // Build the secret name. + ProjectName projectName = ProjectName.of(projectId); + + // Build the Cmek configuration. + CustomerManagedEncryption customerManagedEncryption = + CustomerManagedEncryption.newBuilder().setKmsKeyName(kmsKeyName).build(); + + // Build the replication using Cmek. + Replication secretReplication = + Replication.newBuilder() + .setAutomatic( + Replication.Automatic.newBuilder() + .setCustomerManagedEncryption(customerManagedEncryption) + .build()) + .build(); + + // Build the secret to create with labels. + Secret secret = Secret.newBuilder().setReplication(secretReplication).build(); + + // Create the secret. + Secret createdSecret = client.createSecret(projectName, secretId, secret); + System.out.printf("Created secret %s\n", createdSecret.getName()); + return createdSecret; + } + } +} +// [END secretmanager_create_secret_with_annotations] diff --git a/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java new file mode 100644 index 00000000000..679d57b357b --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java @@ -0,0 +1,77 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_delete_secret_annotations] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class DeleteSecretAnnotations { + + public static void main() throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + deleteSecretAnnotations(projectId, secretId); + } + + // Delete annotations from an existing secret. + public static Secret deleteSecretAnnotations(String projectId, String secretId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the name of the secret. + SecretName secretName = SecretName.of(projectId, secretId); + + // Get the current secret + Secret existingSecret = client.getSecret(secretName); + + // Remove all annotations + Map existingAnnotationsMap = + new HashMap(existingSecret.getAnnotationsMap()); + existingAnnotationsMap.clear(); + + // Build the updated secret. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .putAllAnnotations(existingAnnotationsMap) + .build(); + + // Create the field mask for updating only the annotations + FieldMask fieldMask = FieldMaskUtil.fromString("annotations"); + + // Update the secret. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Deleted annotations from %s\n", updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_delete_secret_annotations] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java new file mode 100644 index 00000000000..21f139bfad6 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java @@ -0,0 +1,75 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_create_regional_secret_with_cmek] +import com.google.cloud.secretmanager.v1.CustomerManagedEncryption; +import com.google.cloud.secretmanager.v1.LocationName; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import java.io.IOException; + +public class CreateRegionalSecretWithCmek { + + public static void main() throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + // This is the Full kms key name to be used for Cmek. + String kmsKeyName = "your-kms-key-name"; + createRegionalSecretWithCmek(projectId, locationId, secretId, kmsKeyName); + } + + // Create a new regional secret with customer-managed encryption key. + public static Secret createRegionalSecretWithCmek( + String projectId, String locationId, String secretId, String kmsKeyName) throws IOException { + + // Endpoint to call the regional secret manager server + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the parent name from the project and location. + LocationName locationName = LocationName.of(projectId, locationId); + + // Build the customer-managed encryption configuration. + CustomerManagedEncryption customerManagedEncryption = + CustomerManagedEncryption.newBuilder().setKmsKeyName(kmsKeyName).build(); + + // Build the secret with customer-managed encryption key. + Secret secret = + Secret.newBuilder().setCustomerManagedEncryption(customerManagedEncryption).build(); + + // Create the secret. + Secret createdSecret = client.createSecret(locationName.toString(), secretId, secret); + System.out.printf("Created secret %s\n", createdSecret.getName()); + return createdSecret; + } + } +} +// [END secretmanager_create_regional_secret_with_cmek] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java new file mode 100644 index 00000000000..ddd4c46fa40 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java @@ -0,0 +1,88 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_delete_regional_secret_annotations] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class DeleteRegionalSecretAnnotations { + + public static void main() throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + deleteRegionalSecretAnnotations(projectId, locationId, secretId); + } + + // Delete annotations from an existing regional secret. + public static Secret deleteRegionalSecretAnnotations( + String projectId, String locationId, String secretId) throws IOException { + + // Endpoint to call the regional secret manager server + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the name of the secret. + SecretName secretName = + SecretName.ofProjectLocationSecretName(projectId, locationId, secretId); + + // Get the current secret + Secret existingSecret = client.getSecret(secretName); + + // Remove all annotations + Map existingAnnotationsMap = + new HashMap(existingSecret.getAnnotationsMap()); + existingAnnotationsMap.clear(); + + // Build the updated secret. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .putAllAnnotations(existingAnnotationsMap) + .build(); + + // Create the field mask for updating only the annotations + FieldMask fieldMask = FieldMaskUtil.fromString("annotations"); + + // Update the secret. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Deleted annotations from %s\n", updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_delete_regional_secret_annotations] diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index 41f88a1e6d9..81d58119be4 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import com.google.api.gax.longrunning.OperationFuture; import com.google.cloud.resourcemanager.v3.CreateTagKeyMetadata; @@ -77,11 +78,13 @@ public class SnippetsIT { private static final String IAM_USER = "serviceAccount:iam-samples@java-docs-samples-testing.iam.gserviceaccount.com"; private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private static final String KMS_KEY_NAME = System.getenv("GOOGLE_CLOUD_KMS_KEY"); private static final String LABEL_KEY = "examplelabelkey"; private static final String LABEL_VALUE = "examplelabelvalue"; private static final String UPDATED_LABEL_KEY = "updatedlabelkey"; private static final String UPDATED_LABEL_VALUE = "updatedlabelvalue"; - private static final String ANNOTATION_KEY = "exampleannotationkey"; + private static final String ANNOTATION_KEY = + "exampleannotationkey"; private static final String ANNOTATION_VALUE = "exampleannotationvalue"; private static final String UPDATED_ANNOTATION_KEY = "updatedannotationkey"; private static final String UPDATED_ANNOTATION_VALUE = "updatedannotationvalue"; @@ -96,6 +99,7 @@ public class SnippetsIT { private static SecretName TEST_SECRET_WITH_LABEL_TO_CREATE_NAME; private static SecretName TEST_SECRET_WITH_TAGS_TO_CREATE_NAME; private static SecretName TEST_SECRET_WITH_ANNOTATION_TO_CREATE_NAME; + private static SecretName TEST_SECRET_WITH_CMEK_TO_CREATE_NAME; private static SecretName TEST_UMMR_SECRET_TO_CREATE_NAME; private static SecretVersion TEST_SECRET_VERSION; private static SecretVersion TEST_SECRET_VERSION_TO_DESTROY; @@ -125,6 +129,7 @@ public static void beforeAll() throws Exception { TEST_SECRET_WITH_TAGS_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_LABEL_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_ANNOTATION_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); + TEST_SECRET_WITH_CMEK_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_VERSION = addSecretVersion(TEST_SECRET_WITH_VERSIONS); TEST_SECRET_VERSION_TO_DESTROY = addSecretVersion(TEST_SECRET_WITH_VERSIONS); @@ -154,12 +159,14 @@ public void afterEach() { @AfterClass public static void afterAll() throws Exception { Assert.assertFalse("missing GOOGLE_CLOUD_PROJECT", Strings.isNullOrEmpty(PROJECT_ID)); + Assert.assertFalse("missing GOOGLE_CLOUD_KMS_KEY", Strings.isNullOrEmpty(KMS_KEY_NAME)); deleteSecret(TEST_SECRET.getName()); deleteSecret(TEST_SECRET_TO_CREATE_NAME.toString()); deleteSecret(TEST_SECRET_WITH_TAGS_TO_CREATE_NAME.toString()); deleteSecret(TEST_SECRET_WITH_LABEL_TO_CREATE_NAME.toString()); deleteSecret(TEST_SECRET_WITH_ANNOTATION_TO_CREATE_NAME.toString()); + deleteSecret(TEST_SECRET_WITH_CMEK_TO_CREATE_NAME.toString()); deleteSecret(TEST_UMMR_SECRET_TO_CREATE_NAME.toString()); deleteSecret(TEST_SECRET_TO_DELETE.getName()); deleteSecret(TEST_SECRET_TO_DELETE_WITH_ETAG.getName()); @@ -367,6 +374,16 @@ public void testCreateSecretWithAnnotations() throws IOException { assertThat(secret.getAnnotationsMap()).containsEntry(ANNOTATION_KEY, ANNOTATION_VALUE); } + @Test + public void testCreateSecretWithCmek() throws IOException { + SecretName name = TEST_SECRET_WITH_CMEK_TO_CREATE_NAME; + Secret secret = CreateSecretWithCmek.createSecretWithCmek( + name.getProject(), name.getSecret(), KMS_KEY_NAME); + + assertThat(secret.getReplication().getAutomatic().getCustomerManagedEncryption() + .getKmsKeyName()).isEqualTo(KMS_KEY_NAME); + } + @Test public void testCreateSecretWithUserManagedReplication() throws IOException { SecretName name = TEST_UMMR_SECRET_TO_CREATE_NAME; @@ -581,6 +598,15 @@ public void testEditSecretAnnotations() throws IOException { UPDATED_ANNOTATION_KEY, UPDATED_ANNOTATION_VALUE); } + @Test + public void testDeleteSecretAnnotations() throws IOException { + SecretName name = SecretName.parse(TEST_SECRET.getName()); + Secret updatedSecret = + DeleteSecretAnnotations.deleteSecretAnnotations(name.getProject(), name.getSecret()); + + assertTrue(updatedSecret.getAnnotationsMap().isEmpty()); + } + @Test public void testUpdateSecretWithAlias() throws IOException { SecretName name = SecretName.parse(TEST_SECRET_WITH_VERSIONS.getName()); diff --git a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java index 11ca876dc30..59aab3567bf 100644 --- a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java @@ -83,6 +83,8 @@ public class SnippetsIT { private static final String IAM_USER = "serviceAccount:iam-samples@java-docs-samples-testing.iam.gserviceaccount.com"; private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private static final String REGIONAL_KMS_KEY_NAME = + System.getenv("GOOGLE_CLOUD_REGIONAL_KMS_KEY"); private static final String LABEL_KEY = "examplelabelkey"; private static final String LABEL_VALUE = "examplelabelvalue"; private static final String UPDATED_LABEL_KEY = "updatedlabelkey"; @@ -105,6 +107,7 @@ public class SnippetsIT { private static SecretName TEST_REGIONAL_SECRET_WITH_LABEL_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_WITH_TAGS_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_WITH_ANNOTATION_TO_CREATE_NAME; + private static SecretName TEST_REGIONAL_SECRET_WITH_CMEK_TO_CREATE_NAME; private static SecretVersion TEST_REGIONAL_SECRET_VERSION; private static SecretVersion TEST_REGIONAL_SECRET_VERSION_TO_DESTROY; private static SecretVersion TEST_REGIONAL_SECRET_VERSION_TO_DESTROY_WITH_ETAG; @@ -123,6 +126,8 @@ public static void beforeAll() throws Exception { Assert.assertFalse("missing GOOGLE_CLOUD_PROJECT", Strings.isNullOrEmpty(PROJECT_ID)); Assert.assertFalse("missing GOOGLE_CLOUD_PROJECT_LOCATION", Strings.isNullOrEmpty(LOCATION_ID)); + Assert.assertFalse("missing REGIONAL_KMS_KEY_NAME", + Strings.isNullOrEmpty(REGIONAL_KMS_KEY_NAME)); TEST_REGIONAL_SECRET = createRegionalSecret(); TEST_REGIONAL_SECRET_TO_DELETE = createRegionalSecret(); @@ -135,6 +140,8 @@ public static void beforeAll() throws Exception { SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); TEST_REGIONAL_SECRET_WITH_ANNOTATION_TO_CREATE_NAME = SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); + TEST_REGIONAL_SECRET_WITH_CMEK_TO_CREATE_NAME = + SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); TEST_REGIONAL_SECRET_WITH_LABEL_TO_CREATE_NAME = SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); @@ -180,6 +187,7 @@ public static void afterAll() throws Exception { deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_LABEL_TO_CREATE_NAME.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_TAGS_TO_CREATE_NAME.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_ANNOTATION_TO_CREATE_NAME.toString()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_CMEK_TO_CREATE_NAME.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELETE.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELETE_WITH_ETAG.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_VERSIONS.getName()); @@ -398,6 +406,17 @@ public void testCreateRegionalSecretWithAnnotations() throws IOException { assertEquals(name.getSecret(), createdSecretName.getSecret()); } + @Test + public void testCreateRegionalSecretWithCmek() throws IOException { + SecretName name = TEST_REGIONAL_SECRET_WITH_CMEK_TO_CREATE_NAME; + Secret secret = CreateRegionalSecretWithCmek.createRegionalSecretWithCmek( + name.getProject(), name.getLocation(), name.getSecret(), REGIONAL_KMS_KEY_NAME); + + assertThat( + secret.getCustomerManagedEncryption().getKmsKeyName() + ).isEqualTo(REGIONAL_KMS_KEY_NAME); + } + @Test public void testDeleteRegionalSecret() throws IOException { SecretName name = SecretName.parse(TEST_REGIONAL_SECRET_TO_DELETE.getName()); @@ -682,6 +701,16 @@ public void testEditSecretAnnotations() throws IOException { UPDATED_ANNOTATION_KEY, UPDATED_ANNOTATION_VALUE); } + @Test + public void testDeleteRegionalSecretAnnotations() throws IOException { + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET.getName()); + Secret updatedSecret = DeleteRegionalSecretAnnotations.deleteRegionalSecretAnnotations( + name.getProject(), name.getLocation(), name.getSecret()); + + assertTrue(updatedSecret.getAnnotationsMap().isEmpty()); + } + + @Test public void testCreateRegionalSecretWithDelayedDestroy() throws IOException { SecretName name = TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY; From 36203bb30aefeab19e4c0ca7168d01fa0a8f341f Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Wed, 21 Jan 2026 11:30:47 +0530 Subject: [PATCH 02/11] Improved readme and created new secret specific for deleting annotations --- secretmanager/README.md | 3 ++- secretmanager/src/test/java/secretmanager/SnippetsIT.java | 5 ++++- .../test/java/secretmanager/regionalsamples/SnippetsIT.java | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/secretmanager/README.md b/secretmanager/README.md index 0ffcc0d9ec0..72e712540d1 100644 --- a/secretmanager/README.md +++ b/secretmanager/README.md @@ -12,7 +12,7 @@ the Secret Manager API using the Google Java API Client Libraries. ### Enable the API -You must [enable the Secret Manager API](https://console.cloud.google.com/flows/enableapi?apiid=secretmanager.googleapis.com) for your project in order to use these samples +You must enable the [Secret Manager API](https://console.cloud.google.com/flows/enableapi?apiid=secretmanager.googleapis.com) and [Cloud KMS API](https://console.cloud.google.com/flows/enableapi?apiid=cloudkms.googleapis.com) for your project in order to use these samples ### Set Environment Variables @@ -30,5 +30,6 @@ You must ensure that the [user account or service account](https://cloud.google. * Secret Manager Admin (`roles/secretmanager.admin`) * Secret Manager Secret Accessor (`roles/secretmanager.secretAccessor`) +* Cloud KMS Encrypter / Decrypter (`roles/cloudkms.cryptoKeyEncrypterDecrypter`) on the regional and global KMS key used for testing More information can be found in the [Secret Manager Docs](https://cloud.google.com/secret-manager/docs/access-control) diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index 81d58119be4..e2c6a362a45 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -92,6 +92,7 @@ public class SnippetsIT { private static Secret TEST_SECRET; private static Secret TEST_SECRET_TO_DELETE; private static Secret TEST_SECRET_TO_DELETE_WITH_ETAG; + private static Secret TEST_SECRET_TO_DELETE_ANNOTATIONS; private static Secret TEST_SECRET_TO_DELAYED_DESTROY; private static Secret TEST_SECRET_WITH_VERSIONS; private static SecretName TEST_SECRET_WITH_DELAYED_DESTROY; @@ -121,6 +122,7 @@ public static void beforeAll() throws Exception { TEST_SECRET = createSecret(true); TEST_SECRET_TO_DELETE = createSecret(false); TEST_SECRET_TO_DELETE_WITH_ETAG = createSecret(false); + TEST_SECRET_TO_DELETE_ANNOTATIONS = createSecret(true); TEST_SECRET_WITH_VERSIONS = createSecret(false); TEST_SECRET_TO_DELAYED_DESTROY = createSecret(false); TEST_SECRET_WITH_DELAYED_DESTROY = SecretName.of(PROJECT_ID, randomSecretId()); @@ -170,6 +172,7 @@ public static void afterAll() throws Exception { deleteSecret(TEST_UMMR_SECRET_TO_CREATE_NAME.toString()); deleteSecret(TEST_SECRET_TO_DELETE.getName()); deleteSecret(TEST_SECRET_TO_DELETE_WITH_ETAG.getName()); + deleteSecret(TEST_SECRET_TO_DELETE_ANNOTATIONS.getName()); deleteSecret(TEST_SECRET_WITH_VERSIONS.getName()); deleteSecret(TEST_SECRET_WITH_DELAYED_DESTROY.toString()); deleteSecret(TEST_SECRET_TO_DELAYED_DESTROY.getName()); @@ -600,7 +603,7 @@ public void testEditSecretAnnotations() throws IOException { @Test public void testDeleteSecretAnnotations() throws IOException { - SecretName name = SecretName.parse(TEST_SECRET.getName()); + SecretName name = SecretName.parse(TEST_SECRET_TO_DELETE_ANNOTATIONS.getName()); Secret updatedSecret = DeleteSecretAnnotations.deleteSecretAnnotations(name.getProject(), name.getSecret()); diff --git a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java index 59aab3567bf..067a69b1e33 100644 --- a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java @@ -100,6 +100,7 @@ public class SnippetsIT { private static Secret TEST_REGIONAL_SECRET; private static Secret TEST_REGIONAL_SECRET_TO_DELETE; private static Secret TEST_REGIONAL_SECRET_TO_DELETE_WITH_ETAG; + private static Secret TEST_REGIONAL_SECRET_TO_DELETE_ANNOTATIONS; private static Secret TEST_REGIONAL_SECRET_WITH_VERSIONS; private static Secret TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY; private static SecretName TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY; @@ -132,6 +133,7 @@ public static void beforeAll() throws Exception { TEST_REGIONAL_SECRET = createRegionalSecret(); TEST_REGIONAL_SECRET_TO_DELETE = createRegionalSecret(); TEST_REGIONAL_SECRET_TO_DELETE_WITH_ETAG = createRegionalSecret(); + TEST_REGIONAL_SECRET_TO_DELETE_ANNOTATIONS = createRegionalSecret(); TEST_REGIONAL_SECRET_WITH_VERSIONS = createRegionalSecret(); TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY = createRegionalSecret(); TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY = @@ -190,6 +192,7 @@ public static void afterAll() throws Exception { deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_CMEK_TO_CREATE_NAME.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELETE.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELETE_WITH_ETAG.getName()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELETE_ANNOTATIONS.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_VERSIONS.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY.getName()); @@ -703,7 +706,7 @@ public void testEditSecretAnnotations() throws IOException { @Test public void testDeleteRegionalSecretAnnotations() throws IOException { - SecretName name = SecretName.parse(TEST_REGIONAL_SECRET.getName()); + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET_TO_DELETE_ANNOTATIONS.getName()); Secret updatedSecret = DeleteRegionalSecretAnnotations.deleteRegionalSecretAnnotations( name.getProject(), name.getLocation(), name.getSecret()); From 0acae1650bc78396a90c357f974dcb8ddbafb5c2 Mon Sep 17 00:00:00 2001 From: dhavalbhensdadiya-crest Date: Wed, 21 Jan 2026 11:38:44 +0530 Subject: [PATCH 03/11] Applied suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../java/secretmanager/CreateSecretWithCmek.java | 8 ++++---- .../java/secretmanager/DeleteSecretAnnotations.java | 12 ++---------- .../DeleteRegionalSecretAnnotations.java | 12 ++---------- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java index b185047a2e0..64d23cceefd 100644 --- a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java @@ -16,7 +16,7 @@ package secretmanager; -// [START secretmanager_create_secret_with_annotations] +// [START secretmanager_create_secret_with_cmek] import com.google.cloud.secretmanager.v1.CustomerManagedEncryption; import com.google.cloud.secretmanager.v1.ProjectName; import com.google.cloud.secretmanager.v1.Replication; @@ -38,7 +38,7 @@ public static void main() throws IOException { createSecretWithCmek(projectId, secretId, kmsKeyName); } - // Create a secret with annotations. + // Create a secret with a customer-managed encryption key (CMEK). public static Secret createSecretWithCmek(String projectId, String secretId, String kmsKeyName) throws IOException { @@ -63,7 +63,7 @@ public static Secret createSecretWithCmek(String projectId, String secretId, Str .build()) .build(); - // Build the secret to create with labels. + // Build the secret to create with the replication policy. Secret secret = Secret.newBuilder().setReplication(secretReplication).build(); // Create the secret. @@ -73,4 +73,4 @@ public static Secret createSecretWithCmek(String projectId, String secretId, Str } } } -// [END secretmanager_create_secret_with_annotations] +// [END secretmanager_create_secret_with_cmek] diff --git a/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java index 679d57b357b..20a6f9cc5cb 100644 --- a/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java +++ b/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java @@ -48,19 +48,11 @@ public static Secret deleteSecretAnnotations(String projectId, String secretId) // Build the name of the secret. SecretName secretName = SecretName.of(projectId, secretId); - // Get the current secret - Secret existingSecret = client.getSecret(secretName); - - // Remove all annotations - Map existingAnnotationsMap = - new HashMap(existingSecret.getAnnotationsMap()); - existingAnnotationsMap.clear(); - - // Build the updated secret. + // Build the updated secret with an empty annotations map. Secret secret = Secret.newBuilder() .setName(secretName.toString()) - .putAllAnnotations(existingAnnotationsMap) + .putAllAnnotations(new HashMap<>()) .build(); // Create the field mask for updating only the annotations diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java index ddd4c46fa40..fd34f0db992 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java @@ -59,19 +59,11 @@ public static Secret deleteRegionalSecretAnnotations( SecretName secretName = SecretName.ofProjectLocationSecretName(projectId, locationId, secretId); - // Get the current secret - Secret existingSecret = client.getSecret(secretName); - - // Remove all annotations - Map existingAnnotationsMap = - new HashMap(existingSecret.getAnnotationsMap()); - existingAnnotationsMap.clear(); - - // Build the updated secret. + // Build the updated secret with an empty annotations map. Secret secret = Secret.newBuilder() .setName(secretName.toString()) - .putAllAnnotations(existingAnnotationsMap) + .putAllAnnotations(new HashMap<>()) .build(); // Create the field mask for updating only the annotations From 9d6e4ee2d3e7adf475b49165638efe78a20c8c39 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Thu, 22 Jan 2026 12:49:52 +0530 Subject: [PATCH 04/11] Added args to main function --- .../src/main/java/secretmanager/CreateSecretWithCmek.java | 2 +- .../src/main/java/secretmanager/DeleteSecretAnnotations.java | 4 ++-- .../regionalsamples/CreateRegionalSecretWithCmek.java | 2 +- .../regionalsamples/DeleteRegionalSecretAnnotations.java | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java index 64d23cceefd..4f4fae9f911 100644 --- a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java @@ -26,7 +26,7 @@ public class CreateSecretWithCmek { - public static void main() throws IOException { + public static void main(String[] args) throws IOException { // TODO(developer): Replace these variables before running the sample. // This is the id of the GCP project diff --git a/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java index 20a6f9cc5cb..c689d1bc813 100644 --- a/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java +++ b/secretmanager/src/main/java/secretmanager/DeleteSecretAnnotations.java @@ -24,11 +24,11 @@ import com.google.protobuf.util.FieldMaskUtil; import java.io.IOException; import java.util.HashMap; -import java.util.Map; public class DeleteSecretAnnotations { - public static void main() throws IOException { + + public static void main(String[] args) throws IOException { // TODO(developer): Replace these variables before running the sample. // This is the id of the GCP project diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java index 21f139bfad6..ac52811d658 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java @@ -26,7 +26,7 @@ public class CreateRegionalSecretWithCmek { - public static void main() throws IOException { + public static void main(String[] args) throws IOException { // TODO(developer): Replace these variables before running the sample. // This is the id of the GCP project diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java index fd34f0db992..babbd3ef636 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java @@ -25,11 +25,10 @@ import com.google.protobuf.util.FieldMaskUtil; import java.io.IOException; import java.util.HashMap; -import java.util.Map; public class DeleteRegionalSecretAnnotations { - public static void main() throws IOException { + public static void main(String[] args) throws IOException { // TODO(developer): Replace these variables before running the sample. // This is the id of the GCP project From 710bb85be44637d01d776403c2ae197b9cd314f0 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Thu, 22 Jan 2026 15:36:43 +0530 Subject: [PATCH 05/11] Moved KMS key validation check to BeforeClass setup --- secretmanager/src/test/java/secretmanager/SnippetsIT.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index e2c6a362a45..fd219a3607a 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -118,6 +118,7 @@ public class SnippetsIT { @BeforeClass public static void beforeAll() throws Exception { Assert.assertFalse("missing GOOGLE_CLOUD_PROJECT", Strings.isNullOrEmpty(PROJECT_ID)); + Assert.assertFalse("missing GOOGLE_CLOUD_KMS_KEY", Strings.isNullOrEmpty(KMS_KEY_NAME)); TEST_SECRET = createSecret(true); TEST_SECRET_TO_DELETE = createSecret(false); @@ -160,8 +161,6 @@ public void afterEach() { @AfterClass public static void afterAll() throws Exception { - Assert.assertFalse("missing GOOGLE_CLOUD_PROJECT", Strings.isNullOrEmpty(PROJECT_ID)); - Assert.assertFalse("missing GOOGLE_CLOUD_KMS_KEY", Strings.isNullOrEmpty(KMS_KEY_NAME)); deleteSecret(TEST_SECRET.getName()); deleteSecret(TEST_SECRET_TO_CREATE_NAME.toString()); From bfbc85c510c580636a9cd8af80a0f5d6d824cb50 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Thu, 22 Jan 2026 11:44:21 +0530 Subject: [PATCH 06/11] feat(secretmanager): add examples for listing, binding and removing tags from secrets --- .../java/secretmanager/BindSecretTag.java | 64 ++++++++++++++++ .../secretmanager/ListSecretTagBindings.java | 58 +++++++++++++++ .../secretmanager/RemoveTagFromSecret.java | 64 ++++++++++++++++ .../BindRegionalSecretTag.java | 74 +++++++++++++++++++ .../ListRegionalSecretTagBindings.java | 66 +++++++++++++++++ .../RemoveTagFromRegionalSecret.java | 74 +++++++++++++++++++ .../test/java/secretmanager/SnippetsIT.java | 33 +++++++++ .../regionalsamples/SnippetsIT.java | 39 ++++++++++ 8 files changed, 472 insertions(+) create mode 100644 secretmanager/src/main/java/secretmanager/BindSecretTag.java create mode 100644 secretmanager/src/main/java/secretmanager/ListSecretTagBindings.java create mode 100644 secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/BindRegionalSecretTag.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/ListRegionalSecretTagBindings.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java diff --git a/secretmanager/src/main/java/secretmanager/BindSecretTag.java b/secretmanager/src/main/java/secretmanager/BindSecretTag.java new file mode 100644 index 00000000000..fb18ad4bff3 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/BindSecretTag.java @@ -0,0 +1,64 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_bind_secret_tag] +import com.google.cloud.resourcemanager.v3.CreateTagBindingRequest; +import com.google.cloud.resourcemanager.v3.TagBinding; +import com.google.cloud.resourcemanager.v3.TagBindingsClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class BindSecretTag { + + public static void main(String[] args) throws Exception { + // TODO(developer): replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + // Tag value to bind, e.g. "tagValues/123" + String tagValueName = "your-tag-value"; + + bindSecretTag(projectId, secretId, tagValueName); + } + + // Bind a TagValue to a Secret by creating a TagBinding. + public static TagBinding bindSecretTag(String projectId, String secretId, String tagValueName) + throws IOException, InterruptedException, ExecutionException { + + String parent = String.format("//secretmanager.googleapis.com/projects/%s/secrets/%s", + projectId, secretId); + + try (TagBindingsClient tagBindingsClient = TagBindingsClient.create()) { + TagBinding tagBinding = TagBinding.newBuilder() + .setTagValue(tagValueName) + .setParent(parent) + .build(); + + CreateTagBindingRequest request = CreateTagBindingRequest.newBuilder() + .setTagBinding(tagBinding) + .build(); + + TagBinding created = tagBindingsClient.createTagBindingAsync(request).get(); + System.out.printf("Created TagBinding: %s\n", created.getName()); + return created; + } + } +} +// [END secretmanager_bind_secret_tag] diff --git a/secretmanager/src/main/java/secretmanager/ListSecretTagBindings.java b/secretmanager/src/main/java/secretmanager/ListSecretTagBindings.java new file mode 100644 index 00000000000..2b05832e9cd --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/ListSecretTagBindings.java @@ -0,0 +1,58 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_list_secret_tag_bindings] +import com.google.cloud.resourcemanager.v3.ListTagBindingsRequest; +import com.google.cloud.resourcemanager.v3.TagBinding; +import com.google.cloud.resourcemanager.v3.TagBindingsClient; +import java.io.IOException; + +public class ListSecretTagBindings { + + public static void main(String[] args) throws Exception { + // TODO(developer): replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + + listSecretTagBindings(projectId, secretId); + } + + // List tag bindings attached to the secret resource. + public static void listSecretTagBindings(String projectId, String secretId) + throws IOException { + + // Resource Manager TagBindings are listed under a parent such as the project. + String parent = String.format("//secretmanager.googleapis.com/projects/%s/secrets/%s", + projectId, secretId); + + try (TagBindingsClient tagBindingsClient = TagBindingsClient.create()) { + ListTagBindingsRequest request = + ListTagBindingsRequest.newBuilder().setParent(parent).build(); + + // Iterate over tag bindings + for (TagBinding binding : tagBindingsClient.listTagBindings(request).iterateAll()) { + System.out.printf("Found TagBinding with Name %s and TagValue %s\n", + binding.getName(), binding.getTagValue()); + } + } + } +} +// [END secretmanager_list_secret_tag_bindings] diff --git a/secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java b/secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java new file mode 100644 index 00000000000..c17527f1d8b --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java @@ -0,0 +1,64 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_remove_tag_from_secret] +import com.google.cloud.resourcemanager.v3.ListTagBindingsRequest; +import com.google.cloud.resourcemanager.v3.TagBinding; +import com.google.cloud.resourcemanager.v3.TagBindingsClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class RemoveTagFromSecret { + + public static void main(String[] args) throws Exception { + // TODO(developer): replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + // Tag value to remove, e.g. "tagValues/123" + String tagValueName = "your-tag-value"; + + removeTagFromSecret(projectId, secretId, tagValueName); + } + + // Remove a TagValue from a Secret by deleting the TagBinding. + public static void removeTagFromSecret(String projectId, String secretId, String tagValueName) + throws IOException, InterruptedException, ExecutionException { + + String parent = String.format("//secretmanager.googleapis.com/projects/%s/secrets/%s", + projectId, secretId); + + try (TagBindingsClient tagBindingsClient = TagBindingsClient.create()) { + ListTagBindingsRequest request = + ListTagBindingsRequest.newBuilder().setParent(parent).build(); + + // Iterate over tag bindings + for (TagBinding binding : tagBindingsClient.listTagBindings(request).iterateAll()) { + // Delete the TagBinding if it matches the specified TagValue + if (binding.getTagValue().equals(tagValueName)) { + tagBindingsClient.deleteTagBindingAsync(binding.getName()).get(); + System.out.printf("Deleted TagBinding with Name %s and TagValue %s\n", + binding.getName(), binding.getTagValue()); + } + } + } + } +} +// [END secretmanager_remove_tag_from_secret] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/BindRegionalSecretTag.java b/secretmanager/src/main/java/secretmanager/regionalsamples/BindRegionalSecretTag.java new file mode 100644 index 00000000000..50fda18f101 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/BindRegionalSecretTag.java @@ -0,0 +1,74 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_bind_regional_secret_tag] +import com.google.cloud.resourcemanager.v3.CreateTagBindingRequest; +import com.google.cloud.resourcemanager.v3.TagBinding; +import com.google.cloud.resourcemanager.v3.TagBindingsClient; +import com.google.cloud.resourcemanager.v3.TagBindingsSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class BindRegionalSecretTag { + + public static void main(String[] args) throws Exception { + // TODO(developer): replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + // Tag value to bind, e.g. "tagValues/123" + String tagValueName = "your-tag-value"; + + bindRegionalSecretTag(projectId, locationId, secretId, tagValueName); + } + + // Bind a TagValue to a regional Secret by creating a TagBinding. + public static TagBinding bindRegionalSecretTag( + String projectId, String locationId, String secretId, String tagValueName) + throws IOException, InterruptedException, ExecutionException { + + String parent = String.format( + "//secretmanager.googleapis.com/projects/%s/locations/%s/secrets/%s", + projectId, locationId, secretId); + + // Endpoint to call the regional secret manager server + String apiEndpoint = String.format("%s-cloudresourcemanager.googleapis.com:443", locationId); + TagBindingsSettings tagBindingsSettings = + TagBindingsSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + try (TagBindingsClient tagBindingsClient = TagBindingsClient.create(tagBindingsSettings)) { + TagBinding tagBinding = TagBinding.newBuilder() + .setTagValue(tagValueName) + .setParent(parent) + .build(); + + CreateTagBindingRequest request = CreateTagBindingRequest.newBuilder() + .setTagBinding(tagBinding) + .build(); + + TagBinding created = tagBindingsClient.createTagBindingAsync(request).get(); + System.out.printf("Created TagBinding: %s\n", created.getName()); + return created; + } + } +} +// [END secretmanager_bind_regional_secret_tag] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/ListRegionalSecretTagBindings.java b/secretmanager/src/main/java/secretmanager/regionalsamples/ListRegionalSecretTagBindings.java new file mode 100644 index 00000000000..c853934a31e --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/ListRegionalSecretTagBindings.java @@ -0,0 +1,66 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_list_regional_secret_tag_bindings] +import com.google.cloud.resourcemanager.v3.ListTagBindingsRequest; +import com.google.cloud.resourcemanager.v3.TagBinding; +import com.google.cloud.resourcemanager.v3.TagBindingsClient; +import com.google.cloud.resourcemanager.v3.TagBindingsSettings; +import java.io.IOException; + +public class ListRegionalSecretTagBindings { + + public static void main(String[] args) throws Exception { + // TODO(developer): replace these variables before running the sample. + // This is the id of the GCP project + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + + listRegionalSecretTagBindings(projectId, locationId, secretId); + } + + // List tag bindings attached to the regional secret resource. + public static void listRegionalSecretTagBindings( + String projectId, String locationId, String secretId) throws IOException { + + // Resource Manager TagBindings are listed under a parent such as the project. + String parent = String.format( + "//secretmanager.googleapis.com/projects/%s/locations/%s/secrets/%s", + projectId, locationId, secretId); + + // Endpoint to call the regional secret manager server + String apiEndpoint = String.format("%s-cloudresourcemanager.googleapis.com:443", locationId); + TagBindingsSettings tagBindingsSettings = + TagBindingsSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + try (TagBindingsClient tagBindingsClient = TagBindingsClient.create(tagBindingsSettings)) { + ListTagBindingsRequest request = ListTagBindingsRequest.newBuilder() + .setParent(parent).build(); + + // Iterate over tag bindings + for (TagBinding binding : tagBindingsClient.listTagBindings(request).iterateAll()) { + System.out.printf("Found TagBinding with Name %s and TagValue %s\n", + binding.getName(), binding.getTagValue()); + } + } + } +} +// [END secretmanager_list_regional_secret_tag_bindings] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java b/secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java new file mode 100644 index 00000000000..10b2cba2edb --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java @@ -0,0 +1,74 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_remove_tag_from_regionalsecret] +import com.google.cloud.resourcemanager.v3.ListTagBindingsRequest; +import com.google.cloud.resourcemanager.v3.TagBinding; +import com.google.cloud.resourcemanager.v3.TagBindingsClient; +import com.google.cloud.resourcemanager.v3.TagBindingsSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class RemoveTagFromRegionalSecret { + + public static void main(String[] args) throws Exception { + // TODO(developer): replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // This is the id of the secret to act on + String secretId = "your-secret-id"; + // Tag value to bind, e.g. "tagValues/123" + String tagValueName = "your-tag-value"; + + removeTagFromRegionalSecret(projectId, locationId, secretId, tagValueName); + } + + // Remove a TagValue from a regional Secret by deleting the TagBinding. + public static void removeTagFromRegionalSecret( + String projectId, String locationId, String secretId, String tagValueName) + throws IOException, InterruptedException, ExecutionException { + + String parent = String.format( + "//secretmanager.googleapis.com/projects/%s/locations/%s/secrets/%s", + projectId, locationId, secretId); + + // Endpoint to call the regional secret manager server + String apiEndpoint = String.format("%s-cloudresourcemanager.googleapis.com:443", locationId); + TagBindingsSettings tagBindingsSettings = + TagBindingsSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + try (TagBindingsClient tagBindingsClient = TagBindingsClient.create(tagBindingsSettings)) { + ListTagBindingsRequest request = ListTagBindingsRequest.newBuilder() + .setParent(parent).build(); + + // Iterate over tag bindings + for (TagBinding binding : tagBindingsClient.listTagBindings(request).iterateAll()) { + // Delete the TagBinding if it matches the specified TagValue + if (binding.getTagValue().equals(tagValueName)) { + tagBindingsClient.deleteTagBindingAsync(binding.getName()).get(); + System.out.printf("Deleted TagBinding with Name %s and TagValue %s\n", + binding.getName(), binding.getTagValue()); + } + } + } + } +} +// [END secretmanager_remove_tag_from_regional_secret] diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index fd219a3607a..a7ad69ac456 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -58,6 +58,7 @@ import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.ExecutionException; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -572,6 +573,38 @@ public void testListSecretsWithFilter() throws IOException { assertThat(stdOut.toString()).contains(name.getSecret()); } + @Test + public void testListSecretTagBindings() throws IOException { + SecretName name = TEST_SECRET_WITH_TAGS_TO_CREATE_NAME; + ListSecretTagBindings.listSecretTagBindings(name.getProject(), name.getSecret()); + + assertThat(stdOut.toString()).contains("Found TagBinding"); + } + + @Test + public void testBindSecretTag() throws IOException, InterruptedException, ExecutionException { + SecretName name = SecretName.parse(TEST_SECRET.getName()); + BindSecretTag.bindSecretTag( + name.getProject(), + name.getSecret(), + TAG_VALUE.getName()); + + assertThat(stdOut.toString()).contains("Created TagBinding"); + } + + @Test + public void testRemoveTagFromSecret() + throws IOException, InterruptedException, ExecutionException { + + SecretName name = SecretName.parse(TEST_SECRET.getName()); + RemoveTagFromSecret.removeTagFromSecret( + name.getProject(), + name.getSecret(), + TAG_VALUE.getName()); + + assertThat(stdOut.toString()).contains("Deleted TagBinding"); + } + @Test public void testUpdateSecret() throws IOException { SecretName name = SecretName.parse(TEST_SECRET.getName()); diff --git a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java index 067a69b1e33..7488b5a4e2d 100644 --- a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java @@ -64,6 +64,7 @@ import java.lang.Exception; import java.util.Map; import java.util.Random; +import java.util.concurrent.ExecutionException; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -657,6 +658,44 @@ public void testListRegionalSecretsWithFilter() throws IOException { assertTrue(secretPresentInList); } + @Test + public void testListRegionalSecretTagBindings() throws IOException { + SecretName name = TEST_REGIONAL_SECRET_WITH_TAGS_TO_CREATE_NAME; + ListRegionalSecretTagBindings.listRegionalSecretTagBindings( + name.getProject(), name.getLocation(), name.getSecret() + ); + + assertThat(stdOut.toString()).contains("Found TagBinding"); + } + + @Test + public void testBindRegionalSecretTag() + throws IOException, InterruptedException, ExecutionException { + + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET.getName()); + BindRegionalSecretTag.bindRegionalSecretTag( + name.getProject(), + name.getLocation(), + name.getSecret(), + TAG_VALUE.getName()); + + assertThat(stdOut.toString()).contains("Created TagBinding"); + } + + @Test + public void testRemoveTagFromRegionalSecret() + throws IOException, InterruptedException, ExecutionException { + + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET.getName()); + RemoveTagFromRegionalSecret.removeTagFromRegionalSecret( + name.getProject(), + name.getLocation(), + name.getSecret(), + TAG_VALUE.getName()); + + assertThat(stdOut.toString()).contains("Deleted TagBinding"); + } + @Test public void testEditRegionalSecretLabel() throws IOException { SecretName name = SecretName.parse(TEST_REGIONAL_SECRET.getName()); From c3359019283ca0588d757471431e7a9719f0a438 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Thu, 22 Jan 2026 12:35:15 +0530 Subject: [PATCH 07/11] Renamed files related to delete tags to match existing files --- ...RemoveTagFromSecret.java => DeleteSecretTag.java} | 12 ++++++------ ...ionalSecret.java => DeleteRegionalSecretTag.java} | 10 +++++----- .../src/test/java/secretmanager/SnippetsIT.java | 2 +- .../secretmanager/regionalsamples/SnippetsIT.java | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) rename secretmanager/src/main/java/secretmanager/{RemoveTagFromSecret.java => DeleteSecretTag.java} (86%) rename secretmanager/src/main/java/secretmanager/regionalsamples/{RemoveTagFromRegionalSecret.java => DeleteRegionalSecretTag.java} (90%) diff --git a/secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java b/secretmanager/src/main/java/secretmanager/DeleteSecretTag.java similarity index 86% rename from secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java rename to secretmanager/src/main/java/secretmanager/DeleteSecretTag.java index c17527f1d8b..0d533312ec2 100644 --- a/secretmanager/src/main/java/secretmanager/RemoveTagFromSecret.java +++ b/secretmanager/src/main/java/secretmanager/DeleteSecretTag.java @@ -16,14 +16,14 @@ package secretmanager; -// [START secretmanager_remove_tag_from_secret] +// [START secretmanager_delete_secret_tag] import com.google.cloud.resourcemanager.v3.ListTagBindingsRequest; import com.google.cloud.resourcemanager.v3.TagBinding; import com.google.cloud.resourcemanager.v3.TagBindingsClient; import java.io.IOException; import java.util.concurrent.ExecutionException; -public class RemoveTagFromSecret { +public class DeleteSecretTag { public static void main(String[] args) throws Exception { // TODO(developer): replace these variables before running the sample. @@ -32,14 +32,14 @@ public static void main(String[] args) throws Exception { String projectId = "your-project-id"; // This is the id of the secret to act on String secretId = "your-secret-id"; - // Tag value to remove, e.g. "tagValues/123" + // Tag value to delete, e.g. "tagValues/123" String tagValueName = "your-tag-value"; - removeTagFromSecret(projectId, secretId, tagValueName); + deleteSecretTag(projectId, secretId, tagValueName); } // Remove a TagValue from a Secret by deleting the TagBinding. - public static void removeTagFromSecret(String projectId, String secretId, String tagValueName) + public static void deleteSecretTag(String projectId, String secretId, String tagValueName) throws IOException, InterruptedException, ExecutionException { String parent = String.format("//secretmanager.googleapis.com/projects/%s/secrets/%s", @@ -61,4 +61,4 @@ public static void removeTagFromSecret(String projectId, String secretId, String } } } -// [END secretmanager_remove_tag_from_secret] +// [END secretmanager_delete_secret_tag] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretTag.java similarity index 90% rename from secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java rename to secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretTag.java index 10b2cba2edb..d4e72dbf9b5 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/RemoveTagFromRegionalSecret.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretTag.java @@ -16,7 +16,7 @@ package secretmanager.regionalsamples; -// [START secretmanager_remove_tag_from_regionalsecret] +// [START secretmanager_delete_regional_secret_tag] import com.google.cloud.resourcemanager.v3.ListTagBindingsRequest; import com.google.cloud.resourcemanager.v3.TagBinding; import com.google.cloud.resourcemanager.v3.TagBindingsClient; @@ -24,7 +24,7 @@ import java.io.IOException; import java.util.concurrent.ExecutionException; -public class RemoveTagFromRegionalSecret { +public class DeleteRegionalSecretTag { public static void main(String[] args) throws Exception { // TODO(developer): replace these variables before running the sample. @@ -38,11 +38,11 @@ public static void main(String[] args) throws Exception { // Tag value to bind, e.g. "tagValues/123" String tagValueName = "your-tag-value"; - removeTagFromRegionalSecret(projectId, locationId, secretId, tagValueName); + deleteRegionalSecretTag(projectId, locationId, secretId, tagValueName); } // Remove a TagValue from a regional Secret by deleting the TagBinding. - public static void removeTagFromRegionalSecret( + public static void deleteRegionalSecretTag( String projectId, String locationId, String secretId, String tagValueName) throws IOException, InterruptedException, ExecutionException { @@ -71,4 +71,4 @@ public static void removeTagFromRegionalSecret( } } } -// [END secretmanager_remove_tag_from_regional_secret] +// [END secretmanager_delete_regional_secret_tag] diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index a7ad69ac456..84b43a14189 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -597,7 +597,7 @@ public void testRemoveTagFromSecret() throws IOException, InterruptedException, ExecutionException { SecretName name = SecretName.parse(TEST_SECRET.getName()); - RemoveTagFromSecret.removeTagFromSecret( + DeleteSecretTag.deleteSecretTag( name.getProject(), name.getSecret(), TAG_VALUE.getName()); diff --git a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java index 7488b5a4e2d..1d9b8cc2fed 100644 --- a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java @@ -687,7 +687,7 @@ public void testRemoveTagFromRegionalSecret() throws IOException, InterruptedException, ExecutionException { SecretName name = SecretName.parse(TEST_REGIONAL_SECRET.getName()); - RemoveTagFromRegionalSecret.removeTagFromRegionalSecret( + DeleteRegionalSecretTag.deleteRegionalSecretTag( name.getProject(), name.getLocation(), name.getSecret(), From 15b8d11377cf3d653dc8d9f55f3877ebfc5a0742 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Thu, 22 Jan 2026 15:17:54 +0530 Subject: [PATCH 08/11] feat(secretmanager): add examples for creating, updating and deleting secret expiration times --- .../CreateSecretWithExpiration.java | 77 ++++++++++++++++ .../secretmanager/DeleteSecretExpiration.java | 66 ++++++++++++++ .../secretmanager/UpdateSecretExpiration.java | 78 ++++++++++++++++ .../CreateRegionalSecretWithExpiration.java | 82 +++++++++++++++++ .../DeleteRegionalSecretExpiration.java | 77 ++++++++++++++++ .../UpdateRegionalSecretExpiration.java | 90 +++++++++++++++++++ .../test/java/secretmanager/SnippetsIT.java | 38 ++++++++ .../regionalsamples/SnippetsIT.java | 39 ++++++++ 8 files changed, 547 insertions(+) create mode 100644 secretmanager/src/main/java/secretmanager/CreateSecretWithExpiration.java create mode 100644 secretmanager/src/main/java/secretmanager/DeleteSecretExpiration.java create mode 100644 secretmanager/src/main/java/secretmanager/UpdateSecretExpiration.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretExpiration.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithExpiration.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithExpiration.java new file mode 100644 index 00000000000..c4472edc486 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithExpiration.java @@ -0,0 +1,77 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_create_secret_with_expiration] +import com.google.cloud.secretmanager.v1.ProjectName; +import com.google.cloud.secretmanager.v1.Replication; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.protobuf.Timestamp; +import java.io.IOException; +import java.time.Instant; + +public class CreateSecretWithExpiration { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to create + String secretId = "your-secret-id"; + // This is the time in seconds from now when the secret will expire + long expireTimeSeconds = 86400; // 24 hours + createSecretWithExpiration(projectId, secretId, expireTimeSeconds); + } + + // Create a new secret with an expiration time. + public static Secret createSecretWithExpiration( + String projectId, String secretId, long expireTimeSeconds) throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the parent name from the project. + ProjectName projectName = ProjectName.of(projectId); + + // Calculate the expiration time. + Instant expireTime = Instant.now().plusSeconds(expireTimeSeconds); + Timestamp expireTimestamp = Timestamp.newBuilder() + .setSeconds(expireTime.getEpochSecond()) + .setNanos(expireTime.getNano()) + .build(); + + // Build the secret to create with expiration time. + Secret secret = + Secret.newBuilder() + .setReplication( + Replication.newBuilder() + .setAutomatic(Replication.Automatic.newBuilder().build()) + .build()) + .setExpireTime(expireTimestamp) + .build(); + + // Create the secret. + Secret createdSecret = client.createSecret(projectName, secretId, secret); + System.out.printf("Created secret %s with expire time\n", createdSecret.getName()); + + return createdSecret; + } + } +} +// [END secretmanager_create_secret_with_expiration] diff --git a/secretmanager/src/main/java/secretmanager/DeleteSecretExpiration.java b/secretmanager/src/main/java/secretmanager/DeleteSecretExpiration.java new file mode 100644 index 00000000000..2af3042981d --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/DeleteSecretExpiration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_delete_secret_expiration] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; + +public class DeleteSecretExpiration { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to update + String secretId = "your-secret-id"; + deleteSecretExpiration(projectId, secretId); + } + + // Delete the expiration time from an existing secret. + public static Secret deleteSecretExpiration(String projectId, String secretId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the secret name. + SecretName secretName = SecretName.of(projectId, secretId); + + // Build the updated secret without expiration time. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .build(); + + // Build the field mask to clear the expiration time. + FieldMask fieldMask = FieldMaskUtil.fromString("expire_time"); + + // Update the secret to remove expiration. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Deleted expiration from secret %s\n", updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_delete_secret_expiration] diff --git a/secretmanager/src/main/java/secretmanager/UpdateSecretExpiration.java b/secretmanager/src/main/java/secretmanager/UpdateSecretExpiration.java new file mode 100644 index 00000000000..90cae2fcef3 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/UpdateSecretExpiration.java @@ -0,0 +1,78 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_update_secret_expiration] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; +import java.time.Instant; + +public class UpdateSecretExpiration { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to update + String secretId = "your-secret-id"; + // This is the time in seconds from now when the secret will expire + long expireTimeSeconds = 86400; // 24 hours + updateSecretExpiration(projectId, secretId, expireTimeSeconds); + } + + // Update an existing secret with a new expiration time. + public static Secret updateSecretExpiration( + String projectId, String secretId, long expireTimeSeconds) throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the secret name. + SecretName secretName = SecretName.of(projectId, secretId); + + // Calculate the expiration time. + Instant expireTime = Instant.now().plusSeconds(expireTimeSeconds); + Timestamp expireTimestamp = Timestamp.newBuilder() + .setSeconds(expireTime.getEpochSecond()) + .setNanos(expireTime.getNano()) + .build(); + + // Build the updated secret with new expiration time. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .setExpireTime(expireTimestamp) + .build(); + + // Build the field mask to update only the expiration time. + FieldMask fieldMask = FieldMaskUtil.fromString("expire_time"); + + // Update the secret. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Updated secret %s with new expiration time\n", updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_update_secret_expiration] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java new file mode 100644 index 00000000000..bce2f5c0fb8 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java @@ -0,0 +1,82 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_create_regional_secret_with_expiration] +import com.google.cloud.secretmanager.v1.LocationName; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.protobuf.Timestamp; +import java.io.IOException; +import java.time.Instant; + +public class CreateRegionalSecretWithExpiration { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to create. + String secretId = "your-secret-id"; + // This is the time in seconds from now when the secret will expire. + long expireTimeSeconds = 86400; // 24 hours + createRegionalSecretWithExpiration(projectId, locationId, secretId, expireTimeSeconds); + } + + // Create a new regional secret with an expiration time. + public static Secret createRegionalSecretWithExpiration( + String projectId, String locationId, String secretId, long expireTimeSeconds) + throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the parent name from the project. + LocationName location = LocationName.of(projectId, locationId); + + // Calculate the expiration time. + Instant expireTime = Instant.now().plusSeconds(expireTimeSeconds); + Timestamp expireTimestamp = Timestamp.newBuilder() + .setSeconds(expireTime.getEpochSecond()) + .setNanos(expireTime.getNano()) + .build(); + + // Build the regional secret to create with expiration time. + Secret secret = + Secret.newBuilder() + .setExpireTime(expireTimestamp) + .build(); + + // Create the regional secret. + Secret createdSecret = client.createSecret(location.toString(), secretId, secret); + System.out.printf("Created secret %s with expire time\n", createdSecret.getName()); + + return createdSecret; + } + } +} +// [END secretmanager_create_regional_secret_with_expiration] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretExpiration.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretExpiration.java new file mode 100644 index 00000000000..b4bb5206103 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretExpiration.java @@ -0,0 +1,77 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_delete_regional_secret_expiration] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; + +public class DeleteRegionalSecretExpiration { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to update. + String secretId = "your-secret-id"; + deleteRegionalSecretExpiration(projectId, locationId, secretId); + } + + // Delete the expiration time from an existing regional secret. + public static Secret deleteRegionalSecretExpiration( + String projectId, String locationId, String secretId) throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the secret name. + SecretName secretName = + SecretName.ofProjectLocationSecretName(projectId, locationId, secretId); + + // Build the updated secret without expiration time. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .build(); + + // Build the field mask to clear the expiration time. + FieldMask fieldMask = FieldMaskUtil.fromString("expire_time"); + + // Update the secret to remove expiration. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Deleted expiration from secret %s\n", + updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_delete_regional_secret_expiration] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java b/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java new file mode 100644 index 00000000000..3e675588ecf --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java @@ -0,0 +1,90 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_update_regional_secret_expiration] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; +import java.time.Instant; + +public class UpdateRegionalSecretExpiration { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to update. + String secretId = "your-secret-id"; + // This is the time in seconds from now when the secret will expire. + long expireTimeSeconds = 86400; // 24 hours + updateRegionalSecretExpiration(projectId, locationId, secretId, expireTimeSeconds); + } + + // Update an existing regional secret with a new expiration time. + public static Secret updateRegionalSecretExpiration( + String projectId, String locationId, String secretId, long expireTimeSeconds) + throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the secret name. + SecretName secretName = + SecretName.ofProjectLocationSecretName(projectId, locationId, secretId); + + // Calculate the expiration time. + Instant expireTime = Instant.now().plusSeconds(expireTimeSeconds); + Timestamp expireTimestamp = Timestamp.newBuilder() + .setSeconds(expireTime.getEpochSecond()) + .setNanos(expireTime.getNano()) + .build(); + + // Build the updated secret with new expiration time. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .setExpireTime(expireTimestamp) + .build(); + + // Build the field mask to update only the expiration time. + FieldMask fieldMask = FieldMaskUtil.fromString("expire_time"); + + // Update the secret. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Updated secret %s with new expiration time\n", + updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_update_regional_secret_expiration] diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index 84b43a14189..c50e0eb62b8 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -96,7 +96,9 @@ public class SnippetsIT { private static Secret TEST_SECRET_TO_DELETE_ANNOTATIONS; private static Secret TEST_SECRET_TO_DELAYED_DESTROY; private static Secret TEST_SECRET_WITH_VERSIONS; + private static Secret TEST_SECRET_WITH_EXPIRATION; private static SecretName TEST_SECRET_WITH_DELAYED_DESTROY; + private static SecretName TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME; private static SecretName TEST_SECRET_TO_CREATE_NAME; private static SecretName TEST_SECRET_WITH_LABEL_TO_CREATE_NAME; private static SecretName TEST_SECRET_WITH_TAGS_TO_CREATE_NAME; @@ -134,6 +136,8 @@ public static void beforeAll() throws Exception { TEST_SECRET_WITH_LABEL_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_ANNOTATION_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_CMEK_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); + TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); + TEST_SECRET_WITH_EXPIRATION = createSecret(false); TEST_SECRET_VERSION = addSecretVersion(TEST_SECRET_WITH_VERSIONS); TEST_SECRET_VERSION_TO_DESTROY = addSecretVersion(TEST_SECRET_WITH_VERSIONS); @@ -176,6 +180,8 @@ public static void afterAll() throws Exception { deleteSecret(TEST_SECRET_WITH_VERSIONS.getName()); deleteSecret(TEST_SECRET_WITH_DELAYED_DESTROY.toString()); deleteSecret(TEST_SECRET_TO_DELAYED_DESTROY.getName()); + deleteSecret(TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME.toString()); + deleteSecret(TEST_SECRET_WITH_EXPIRATION.getName()); deleteTags(); } @@ -696,4 +702,36 @@ public void testConsumeEventNotification() { assertThat(log).isEqualTo( "Received SECRET_UPDATE for projects/p/secrets/s. New metadata: hello!"); } + + @Test + public void testCreateSecretWithExpiration() throws IOException { + SecretName name = TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME; + Secret secret = CreateSecretWithExpiration.createSecretWithExpiration( + name.getProject(), name.getSecret(), 86400); + + assertThat(stdOut.toString()).contains("Created secret"); + assertThat(stdOut.toString()).contains("with expire time"); + assertThat(secret.hasExpireTime()).isTrue(); + } + + @Test + public void testUpdateSecretExpiration() throws IOException { + SecretName name = SecretName.parse(TEST_SECRET_WITH_EXPIRATION.getName()); + Secret secret = UpdateSecretExpiration.updateSecretExpiration( + name.getProject(), name.getSecret(), 172800); + + assertThat(stdOut.toString()).contains("Updated secret"); + assertThat(stdOut.toString()).contains("with new expiration time"); + assertThat(secret.hasExpireTime()).isTrue(); + } + + @Test + public void testDeleteSecretExpiration() throws IOException { + SecretName name = SecretName.parse(TEST_SECRET_WITH_EXPIRATION.getName()); + Secret secret = DeleteSecretExpiration.deleteSecretExpiration( + name.getProject(), name.getSecret()); + + assertThat(stdOut.toString()).contains("Deleted expiration from secret"); + assertThat(secret.hasExpireTime()).isFalse(); + } } diff --git a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java index 1d9b8cc2fed..0a20ebe4941 100644 --- a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java @@ -104,7 +104,9 @@ public class SnippetsIT { private static Secret TEST_REGIONAL_SECRET_TO_DELETE_ANNOTATIONS; private static Secret TEST_REGIONAL_SECRET_WITH_VERSIONS; private static Secret TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY; + private static Secret TEST_REGIONAL_SECRET_WITH_EXPIRATION; private static SecretName TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY; + private static SecretName TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_WITH_LABEL_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_WITH_TAGS_TO_CREATE_NAME; @@ -150,6 +152,9 @@ public static void beforeAll() throws Exception { SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); TEST_REGIONAL_SECRET_WITH_TAGS_TO_CREATE_NAME = SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); + TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME = + SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); + TEST_REGIONAL_SECRET_WITH_EXPIRATION = createRegionalSecret(); TEST_REGIONAL_SECRET_VERSION = addRegionalSecretVersion(TEST_REGIONAL_SECRET_WITH_VERSIONS); TEST_REGIONAL_SECRET_VERSION_TO_DESTROY = addRegionalSecretVersion(TEST_REGIONAL_SECRET_WITH_VERSIONS); @@ -197,6 +202,8 @@ public static void afterAll() throws Exception { deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_VERSIONS.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY.getName()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME.toString()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_EXPIRATION.getName()); deleteTags(); } @@ -782,5 +789,37 @@ public void testDisableRegionalSecretDelayedDestroy() throws IOException { assertThat(stdOut.toString()).contains("Updated secret"); assertThat(secret.getVersionDestroyTtl().getSeconds()).isEqualTo(0); } + + @Test + public void testCreateRegionalSecretWithExpiration() throws IOException { + SecretName name = TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME; + Secret secret = CreateRegionalSecretWithExpiration.createRegionalSecretWithExpiration( + name.getProject(), name.getLocation(), name.getSecret(), 86400); + + assertThat(stdOut.toString()).contains("Created secret"); + assertThat(stdOut.toString()).contains("with expire time"); + assertThat(secret.hasExpireTime()).isTrue(); + } + + @Test + public void testUpdateRegionalSecretExpiration() throws IOException { + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET_WITH_EXPIRATION.getName()); + Secret secret = UpdateRegionalSecretExpiration.updateRegionalSecretExpiration( + name.getProject(), name.getLocation(), name.getSecret(), 172800); + + assertThat(stdOut.toString()).contains("Updated secret"); + assertThat(stdOut.toString()).contains("with new expiration time"); + assertThat(secret.hasExpireTime()).isTrue(); + } + + @Test + public void testDeleteRegionalSecretExpiration() throws IOException { + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET_WITH_EXPIRATION.getName()); + Secret secret = DeleteRegionalSecretExpiration.deleteRegionalSecretExpiration( + name.getProject(), name.getLocation(), name.getSecret()); + + assertThat(stdOut.toString()).contains("Deleted expiration from secret"); + assertThat(secret.hasExpireTime()).isFalse(); + } } From dc120be670da68ca9a476f31e59efb2690ad293d Mon Sep 17 00:00:00 2001 From: dhavalbhensdadiya-crest Date: Tue, 27 Jan 2026 14:32:19 +0530 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../src/main/java/secretmanager/CreateSecretWithCmek.java | 3 +-- .../regionalsamples/CreateRegionalSecretWithCmek.java | 2 -- .../regionalsamples/CreateRegionalSecretWithExpiration.java | 3 +-- .../regionalsamples/DeleteRegionalSecretAnnotations.java | 2 -- .../regionalsamples/UpdateRegionalSecretExpiration.java | 3 +-- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java index 4f4fae9f911..4029b1f79ee 100644 --- a/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithCmek.java @@ -42,8 +42,7 @@ public static void main(String[] args) throws IOException { public static Secret createSecretWithCmek(String projectId, String secretId, String kmsKeyName) throws IOException { - // Initialize client that will be used to send requests. This client only needs - // to be created + // Initialize client that will be used to send requests. This client only needs to be created // once, and can be reused for multiple requests. try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java index ac52811d658..9fe6928bda5 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithCmek.java @@ -50,9 +50,7 @@ public static Secret createRegionalSecretWithCmek( SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); // Initialize client that will be used to send requests. This client only needs - // to be created // once, and can be reused for multiple requests. - try (SecretManagerServiceClient client = SecretManagerServiceClient.create(secretManagerServiceSettings)) { // Build the parent name from the project and location. LocationName locationName = LocationName.of(projectId, locationId); diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java index bce2f5c0fb8..f1395bb1e8d 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithExpiration.java @@ -49,8 +49,7 @@ public static Secret createRegionalSecretWithExpiration( // Endpoint to call the regional secret manager sever String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); SecretManagerServiceSettings secretManagerServiceSettings = - SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); - + // created once, and can be reused for multiple requests. // Initialize the client that will be used to send requests. This client only needs to be // created once, and can be reused for multiple requests. try (SecretManagerServiceClient client = diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java index babbd3ef636..e56bc8a6f87 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretAnnotations.java @@ -50,9 +50,7 @@ public static Secret deleteRegionalSecretAnnotations( SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); // Initialize client that will be used to send requests. This client only needs - // to be created // once, and can be reused for multiple requests. - try (SecretManagerServiceClient client = SecretManagerServiceClient.create(secretManagerServiceSettings)) { // Build the name of the secret. SecretName secretName = diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java b/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java index 3e675588ecf..62244dd7d38 100644 --- a/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretExpiration.java @@ -52,8 +52,7 @@ public static Secret updateRegionalSecretExpiration( String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); SecretManagerServiceSettings secretManagerServiceSettings = SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); - - // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. // created once, and can be reused for multiple requests. try (SecretManagerServiceClient client = SecretManagerServiceClient.create(secretManagerServiceSettings)) { From 0805ba200af51a9d463282463b81c9c0f6e89c7f Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Tue, 27 Jan 2026 14:35:21 +0530 Subject: [PATCH 10/11] Resolving Gemini code review comments --- secretmanager/src/test/java/secretmanager/SnippetsIT.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index c50e0eb62b8..ba62867c636 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -84,8 +84,7 @@ public class SnippetsIT { private static final String LABEL_VALUE = "examplelabelvalue"; private static final String UPDATED_LABEL_KEY = "updatedlabelkey"; private static final String UPDATED_LABEL_VALUE = "updatedlabelvalue"; - private static final String ANNOTATION_KEY = - "exampleannotationkey"; + private static final String ANNOTATION_KEY = "exampleannotationkey"; private static final String ANNOTATION_VALUE = "exampleannotationvalue"; private static final String UPDATED_ANNOTATION_KEY = "updatedannotationkey"; private static final String UPDATED_ANNOTATION_VALUE = "updatedannotationvalue"; From 51f9281b3ccfc3edc5e473210faf0546440ce7e5 Mon Sep 17 00:00:00 2001 From: Dhaval Bhensdadiya Date: Tue, 27 Jan 2026 12:28:28 +0530 Subject: [PATCH 11/11] feat(secretmanager): add examples for creating, updating and deleting secret rotation policies and topics --- secretmanager/README.md | 8 +- .../CreateSecretWithRotation.java | 95 +++++++++++++++ .../secretmanager/CreateSecretWithTopic.java | 74 ++++++++++++ .../secretmanager/DeleteSecretRotation.java | 66 +++++++++++ .../secretmanager/UpdateSecretRotation.java | 96 ++++++++++++++++ .../CreateRegionalSecretWithRotation.java | 100 ++++++++++++++++ .../CreateRegionalSecretWithTopic.java | 79 +++++++++++++ .../DeleteRegionalSecretRotation.java | 77 +++++++++++++ .../UpdateRegionalSecretRotation.java | 108 ++++++++++++++++++ .../test/java/secretmanager/SnippetsIT.java | 57 +++++++++ .../regionalsamples/SnippetsIT.java | 59 ++++++++++ 11 files changed, 817 insertions(+), 2 deletions(-) create mode 100644 secretmanager/src/main/java/secretmanager/CreateSecretWithRotation.java create mode 100644 secretmanager/src/main/java/secretmanager/CreateSecretWithTopic.java create mode 100644 secretmanager/src/main/java/secretmanager/DeleteSecretRotation.java create mode 100644 secretmanager/src/main/java/secretmanager/UpdateSecretRotation.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithRotation.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithTopic.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretRotation.java create mode 100644 secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretRotation.java diff --git a/secretmanager/README.md b/secretmanager/README.md index 72e712540d1..417d7d3e76f 100644 --- a/secretmanager/README.md +++ b/secretmanager/README.md @@ -12,18 +12,21 @@ the Secret Manager API using the Google Java API Client Libraries. ### Enable the API -You must enable the [Secret Manager API](https://console.cloud.google.com/flows/enableapi?apiid=secretmanager.googleapis.com) and [Cloud KMS API](https://console.cloud.google.com/flows/enableapi?apiid=cloudkms.googleapis.com) for your project in order to use these samples +You must enable the [Secret Manager API](https://console.cloud.google.com/flows/enableapi?apiid=secretmanager.googleapis.com), [Cloud KMS API](https://console.cloud.google.com/flows/enableapi?apiid=cloudkms.googleapis.com) and [Pub/Sub API](https://console.cloud.google.com/flows/enableapi?apiid=pubsub.googleapis.com) for your project in order to use these samples ### Set Environment Variables -You must set your project ID, KMS Keys (Global and Regional) in order to run the tests +You must set your project ID, KMS Keys (Global and Regional), and Pub/Sub Topic in order to run the tests ```text $ export GOOGLE_CLOUD_PROJECT= $ export GOOGLE_CLOUD_REGIONAL_KMS_KEY= (region same as location) $ export GOOGLE_CLOUD_KMS_KEY= +$ export GOOGLE_CLOUD_PUBSUB_TOPIC= ``` +The Pub/Sub topic should be in the format `projects/PROJECT_ID/topics/TOPIC_ID` and is used for testing secret notifications. + ### Grant Permissions You must ensure that the [user account or service account](https://cloud.google.com/iam/docs/service-accounts#differences_between_a_service_account_and_a_user_account) you used to authorize your gcloud session has the proper permissions to edit Secret Manager resources for your project. In the Cloud Console under IAM, add the following roles to the project whose service account you're using to test: @@ -31,5 +34,6 @@ You must ensure that the [user account or service account](https://cloud.google. * Secret Manager Admin (`roles/secretmanager.admin`) * Secret Manager Secret Accessor (`roles/secretmanager.secretAccessor`) * Cloud KMS Encrypter / Decrypter (`roles/cloudkms.cryptoKeyEncrypterDecrypter`) on the regional and global KMS key used for testing +* Pub/Sub Publisher (`roles/pubsub.publisher`) on the Pub/Sub topic used for testing More information can be found in the [Secret Manager Docs](https://cloud.google.com/secret-manager/docs/access-control) diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithRotation.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithRotation.java new file mode 100644 index 00000000000..9f7ed03f2ee --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithRotation.java @@ -0,0 +1,95 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_create_secret_with_rotation] +import com.google.cloud.secretmanager.v1.ProjectName; +import com.google.cloud.secretmanager.v1.Replication; +import com.google.cloud.secretmanager.v1.Rotation; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.Topic; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import java.io.IOException; +import java.time.Instant; + +public class CreateSecretWithRotation { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to create + String secretId = "your-secret-id"; + // This is the rotation period in seconds (e.g., 2592000 for 30 days) + long rotationPeriodSeconds = 2592000; + // This is the topic name in the format projects/PROJECT_ID/topics/TOPIC_ID + String topicName = "projects/your-project-id/topics/your-topic-id"; + createSecretWithRotation(projectId, secretId, rotationPeriodSeconds, topicName); + } + + // Create a new secret with automatic rotation. + public static Secret createSecretWithRotation( + String projectId, String secretId, long rotationPeriodSeconds, String topicName) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the parent name from the project. + ProjectName projectName = ProjectName.of(projectId); + + // Calculate the next rotation time. + Instant nextRotationTime = Instant.now().plusSeconds(rotationPeriodSeconds); + Timestamp nextRotationTimestamp = Timestamp.newBuilder() + .setSeconds(nextRotationTime.getEpochSecond()) + .setNanos(nextRotationTime.getNano()) + .build(); + + // Build the rotation policy. + Rotation rotation = Rotation.newBuilder() + .setNextRotationTime(nextRotationTimestamp) + .setRotationPeriod(Duration.newBuilder().setSeconds(rotationPeriodSeconds).build()) + .build(); + + // Build the topic for rotation notifications. + Topic topic = Topic.newBuilder() + .setName(topicName) + .build(); + + // Build the secret to create with rotation and topic. + Secret secret = + Secret.newBuilder() + .setReplication( + Replication.newBuilder() + .setAutomatic(Replication.Automatic.newBuilder().build()) + .build()) + .setRotation(rotation) + .addTopics(topic) + .build(); + + // Create the secret. + Secret createdSecret = client.createSecret(projectName, secretId, secret); + System.out.printf("Created secret %s with rotation\n", createdSecret.getName()); + + return createdSecret; + } + } +} +// [END secretmanager_create_secret_with_rotation] diff --git a/secretmanager/src/main/java/secretmanager/CreateSecretWithTopic.java b/secretmanager/src/main/java/secretmanager/CreateSecretWithTopic.java new file mode 100644 index 00000000000..8fd32268cff --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/CreateSecretWithTopic.java @@ -0,0 +1,74 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_create_secret_with_topic] +import com.google.cloud.secretmanager.v1.ProjectName; +import com.google.cloud.secretmanager.v1.Replication; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.Topic; +import java.io.IOException; + +public class CreateSecretWithTopic { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to create + String secretId = "your-secret-id"; + // This is the topic name in the format projects/PROJECT_ID/topics/TOPIC_ID + String topicName = "projects/your-project-id/topics/your-topic-id"; + createSecretWithTopic(projectId, secretId, topicName); + } + + // Create a new secret with a Pub/Sub topic for notifications. + public static Secret createSecretWithTopic( + String projectId, String secretId, String topicName) throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the parent name from the project. + ProjectName projectName = ProjectName.of(projectId); + + // Build the topic. + Topic topic = Topic.newBuilder() + .setName(topicName) + .build(); + + // Build the secret to create with topic. + Secret secret = + Secret.newBuilder() + .setReplication( + Replication.newBuilder() + .setAutomatic(Replication.Automatic.newBuilder().build()) + .build()) + .addTopics(topic) + .build(); + + // Create the secret. + Secret createdSecret = client.createSecret(projectName, secretId, secret); + System.out.printf("Created secret %s with topic\n", createdSecret.getName()); + + return createdSecret; + } + } +} +// [END secretmanager_create_secret_with_topic] diff --git a/secretmanager/src/main/java/secretmanager/DeleteSecretRotation.java b/secretmanager/src/main/java/secretmanager/DeleteSecretRotation.java new file mode 100644 index 00000000000..91a4f1d415d --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/DeleteSecretRotation.java @@ -0,0 +1,66 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_delete_secret_rotation] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; + +public class DeleteSecretRotation { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to update + String secretId = "your-secret-id"; + deleteSecretRotation(projectId, secretId); + } + + // Delete the rotation policy from an existing secret. + public static Secret deleteSecretRotation(String projectId, String secretId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the secret name. + SecretName secretName = SecretName.of(projectId, secretId); + + // Build the updated secret without rotation. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .build(); + + // Build the field mask to clear the rotation. + FieldMask fieldMask = FieldMaskUtil.fromString("rotation"); + + // Update the secret to remove rotation. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Deleted rotation from secret %s\n", updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_delete_secret_rotation] diff --git a/secretmanager/src/main/java/secretmanager/UpdateSecretRotation.java b/secretmanager/src/main/java/secretmanager/UpdateSecretRotation.java new file mode 100644 index 00000000000..34554aedf23 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/UpdateSecretRotation.java @@ -0,0 +1,96 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager; + +// [START secretmanager_update_secret_rotation] +import com.google.cloud.secretmanager.v1.Rotation; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.cloud.secretmanager.v1.Topic; +import com.google.protobuf.Duration; +import com.google.protobuf.FieldMask; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; +import java.time.Instant; + +public class UpdateSecretRotation { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // This is the id of the GCP project + String projectId = "your-project-id"; + // This is the id of the secret to update + String secretId = "your-secret-id"; + // This is the rotation period in seconds (e.g., 2592000 for 30 days) + long rotationPeriodSeconds = 2592000; + // This is the topic name in the format projects/PROJECT_ID/topics/TOPIC_ID + String topicName = "projects/your-project-id/topics/your-topic-id"; + updateSecretRotation(projectId, secretId, rotationPeriodSeconds, topicName); + } + + // Update an existing secret with a new rotation policy. + public static Secret updateSecretRotation( + String projectId, String secretId, long rotationPeriodSeconds, String topicName) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + // Build the secret name. + SecretName secretName = SecretName.of(projectId, secretId); + + // Calculate the next rotation time. + Instant nextRotationTime = Instant.now().plusSeconds(rotationPeriodSeconds); + Timestamp nextRotationTimestamp = Timestamp.newBuilder() + .setSeconds(nextRotationTime.getEpochSecond()) + .setNanos(nextRotationTime.getNano()) + .build(); + + // Build the rotation policy. + Rotation rotation = Rotation.newBuilder() + .setNextRotationTime(nextRotationTimestamp) + .setRotationPeriod(Duration.newBuilder().setSeconds(rotationPeriodSeconds).build()) + .build(); + + // Build the topic for rotation notifications. + Topic topic = Topic.newBuilder() + .setName(topicName) + .build(); + + // Build the updated secret with new rotation policy and topic. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .setRotation(rotation) + .addTopics(topic) + .build(); + + // Build the field mask to update rotation and topics. + FieldMask fieldMask = FieldMaskUtil.fromString("rotation,topics"); + + // Update the secret. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Updated secret %s with new rotation policy\n", updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_update_secret_rotation] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithRotation.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithRotation.java new file mode 100644 index 00000000000..95e75a4a47d --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithRotation.java @@ -0,0 +1,100 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_create_regional_secret_with_rotation] +import com.google.cloud.secretmanager.v1.LocationName; +import com.google.cloud.secretmanager.v1.Rotation; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.Topic; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import java.io.IOException; +import java.time.Instant; + +public class CreateRegionalSecretWithRotation { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to create. + String secretId = "your-secret-id"; + // This is the rotation period in seconds (e.g., 2592000 for 30 days). + long rotationPeriodSeconds = 2592000; + // This is the topic name in the format projects/PROJECT_ID/topics/TOPIC_ID. + String topicName = "projects/your-project-id/topics/your-topic-id"; + createRegionalSecretWithRotation(projectId, locationId, secretId, rotationPeriodSeconds, + topicName); + } + + // Create a new regional secret with automatic rotation. + public static Secret createRegionalSecretWithRotation( + String projectId, String locationId, String secretId, long rotationPeriodSeconds, + String topicName) throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the parent name from the project. + LocationName location = LocationName.of(projectId, locationId); + + // Calculate the next rotation time. + Instant nextRotationTime = Instant.now().plusSeconds(rotationPeriodSeconds); + Timestamp nextRotationTimestamp = Timestamp.newBuilder() + .setSeconds(nextRotationTime.getEpochSecond()) + .setNanos(nextRotationTime.getNano()) + .build(); + + // Build the rotation policy. + Rotation rotation = Rotation.newBuilder() + .setNextRotationTime(nextRotationTimestamp) + .setRotationPeriod(Duration.newBuilder().setSeconds(rotationPeriodSeconds).build()) + .build(); + + // Build the topic for rotation notifications. + Topic topic = Topic.newBuilder() + .setName(topicName) + .build(); + + // Build the regional secret to create with rotation and topic. + Secret secret = + Secret.newBuilder() + .setRotation(rotation) + .addTopics(topic) + .build(); + + // Create the regional secret. + Secret createdSecret = client.createSecret(location.toString(), secretId, secret); + System.out.printf("Created secret %s with rotation\n", createdSecret.getName()); + + return createdSecret; + } + } +} +// [END secretmanager_create_regional_secret_with_rotation] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithTopic.java b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithTopic.java new file mode 100644 index 00000000000..ab9548fd010 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/CreateRegionalSecretWithTopic.java @@ -0,0 +1,79 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_create_regional_secret_with_topic] +import com.google.cloud.secretmanager.v1.LocationName; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.Topic; +import java.io.IOException; + +public class CreateRegionalSecretWithTopic { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to create. + String secretId = "your-secret-id"; + // This is the topic name in the format projects/PROJECT_ID/topics/TOPIC_ID. + String topicName = "projects/your-project-id/topics/your-topic-id"; + createRegionalSecretWithTopic(projectId, locationId, secretId, topicName); + } + + // Create a new regional secret with a Pub/Sub topic for notifications. + public static Secret createRegionalSecretWithTopic( + String projectId, String locationId, String secretId, String topicName) + throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the parent name from the project. + LocationName location = LocationName.of(projectId, locationId); + + // Build the topic. + Topic topic = Topic.newBuilder() + .setName(topicName) + .build(); + + // Build the regional secret to create with topic. + Secret secret = + Secret.newBuilder() + .addTopics(topic) + .build(); + + // Create the regional secret. + Secret createdSecret = client.createSecret(location.toString(), secretId, secret); + System.out.printf("Created secret %s with topic\n", createdSecret.getName()); + + return createdSecret; + } + } +} +// [END secretmanager_create_regional_secret_with_topic] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretRotation.java b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretRotation.java new file mode 100644 index 00000000000..471469998c2 --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/DeleteRegionalSecretRotation.java @@ -0,0 +1,77 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_delete_regional_secret_rotation] +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.protobuf.FieldMask; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; + +public class DeleteRegionalSecretRotation { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to update. + String secretId = "your-secret-id"; + deleteRegionalSecretRotation(projectId, locationId, secretId); + } + + // Delete the rotation policy from an existing regional secret. + public static Secret deleteRegionalSecretRotation( + String projectId, String locationId, String secretId) throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the secret name. + SecretName secretName = + SecretName.ofProjectLocationSecretName(projectId, locationId, secretId); + + // Build the updated secret without rotation. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .build(); + + // Build the field mask to clear the rotation. + FieldMask fieldMask = FieldMaskUtil.fromString("rotation"); + + // Update the secret to remove rotation. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Deleted rotation from secret %s\n", + updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_delete_regional_secret_rotation] diff --git a/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretRotation.java b/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretRotation.java new file mode 100644 index 00000000000..afc0417ad6d --- /dev/null +++ b/secretmanager/src/main/java/secretmanager/regionalsamples/UpdateRegionalSecretRotation.java @@ -0,0 +1,108 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package secretmanager.regionalsamples; + +// [START secretmanager_update_regional_secret_rotation] +import com.google.cloud.secretmanager.v1.Rotation; +import com.google.cloud.secretmanager.v1.Secret; +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings; +import com.google.cloud.secretmanager.v1.SecretName; +import com.google.cloud.secretmanager.v1.Topic; +import com.google.protobuf.Duration; +import com.google.protobuf.FieldMask; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.FieldMaskUtil; +import java.io.IOException; +import java.time.Instant; + +public class UpdateRegionalSecretRotation { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + + // Your GCP project ID. + String projectId = "your-project-id"; + // Location of the secret. + String locationId = "your-location-id"; + // Resource ID of the secret to update. + String secretId = "your-secret-id"; + // This is the rotation period in seconds (e.g., 2592000 for 30 days). + long rotationPeriodSeconds = 2592000; + // This is the topic name in the format projects/PROJECT_ID/topics/TOPIC_ID. + String topicName = "projects/your-project-id/topics/your-topic-id"; + updateRegionalSecretRotation(projectId, locationId, secretId, rotationPeriodSeconds, + topicName); + } + + // Update an existing regional secret with a new rotation policy. + public static Secret updateRegionalSecretRotation( + String projectId, String locationId, String secretId, long rotationPeriodSeconds, + String topicName) throws IOException { + + // Endpoint to call the regional secret manager sever + String apiEndpoint = String.format("secretmanager.%s.rep.googleapis.com:443", locationId); + SecretManagerServiceSettings secretManagerServiceSettings = + SecretManagerServiceSettings.newBuilder().setEndpoint(apiEndpoint).build(); + + // Initialize the client that will be used to send requests. This client only needs to be + // created once, and can be reused for multiple requests. + try (SecretManagerServiceClient client = + SecretManagerServiceClient.create(secretManagerServiceSettings)) { + // Build the secret name. + SecretName secretName = + SecretName.ofProjectLocationSecretName(projectId, locationId, secretId); + + // Calculate the next rotation time. + Instant nextRotationTime = Instant.now().plusSeconds(rotationPeriodSeconds); + Timestamp nextRotationTimestamp = Timestamp.newBuilder() + .setSeconds(nextRotationTime.getEpochSecond()) + .setNanos(nextRotationTime.getNano()) + .build(); + + // Build the rotation policy. + Rotation rotation = Rotation.newBuilder() + .setNextRotationTime(nextRotationTimestamp) + .setRotationPeriod(Duration.newBuilder().setSeconds(rotationPeriodSeconds).build()) + .build(); + + // Build the topic for rotation notifications. + Topic topic = Topic.newBuilder() + .setName(topicName) + .build(); + + // Build the updated secret with new rotation policy and topic. + Secret secret = + Secret.newBuilder() + .setName(secretName.toString()) + .setRotation(rotation) + .addTopics(topic) + .build(); + + // Build the field mask to update rotation and topics. + FieldMask fieldMask = FieldMaskUtil.fromString("rotation,topics"); + + // Update the secret. + Secret updatedSecret = client.updateSecret(secret, fieldMask); + System.out.printf("Updated secret %s with new rotation policy\n", + updatedSecret.getName()); + + return updatedSecret; + } + } +} +// [END secretmanager_update_regional_secret_rotation] diff --git a/secretmanager/src/test/java/secretmanager/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/SnippetsIT.java index ba62867c636..193b623acdb 100644 --- a/secretmanager/src/test/java/secretmanager/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/SnippetsIT.java @@ -80,6 +80,7 @@ public class SnippetsIT { "serviceAccount:iam-samples@java-docs-samples-testing.iam.gserviceaccount.com"; private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); private static final String KMS_KEY_NAME = System.getenv("GOOGLE_CLOUD_KMS_KEY"); + private static final String PUBSUB_TOPIC_NAME = System.getenv("GOOGLE_CLOUD_PUBSUB_TOPIC"); private static final String LABEL_KEY = "examplelabelkey"; private static final String LABEL_VALUE = "examplelabelvalue"; private static final String UPDATED_LABEL_KEY = "updatedlabelkey"; @@ -96,8 +97,11 @@ public class SnippetsIT { private static Secret TEST_SECRET_TO_DELAYED_DESTROY; private static Secret TEST_SECRET_WITH_VERSIONS; private static Secret TEST_SECRET_WITH_EXPIRATION; + private static Secret TEST_SECRET_WITH_ROTATION; private static SecretName TEST_SECRET_WITH_DELAYED_DESTROY; private static SecretName TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME; + private static SecretName TEST_SECRET_WITH_ROTATION_TO_CREATE_NAME; + private static SecretName TEST_SECRET_WITH_TOPIC_TO_CREATE_NAME; private static SecretName TEST_SECRET_TO_CREATE_NAME; private static SecretName TEST_SECRET_WITH_LABEL_TO_CREATE_NAME; private static SecretName TEST_SECRET_WITH_TAGS_TO_CREATE_NAME; @@ -121,6 +125,8 @@ public class SnippetsIT { public static void beforeAll() throws Exception { Assert.assertFalse("missing GOOGLE_CLOUD_PROJECT", Strings.isNullOrEmpty(PROJECT_ID)); Assert.assertFalse("missing GOOGLE_CLOUD_KMS_KEY", Strings.isNullOrEmpty(KMS_KEY_NAME)); + Assert.assertFalse( + "missing GOOGLE_CLOUD_PUBSUB_TOPIC", Strings.isNullOrEmpty(PUBSUB_TOPIC_NAME)); TEST_SECRET = createSecret(true); TEST_SECRET_TO_DELETE = createSecret(false); @@ -136,7 +142,10 @@ public static void beforeAll() throws Exception { TEST_SECRET_WITH_ANNOTATION_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_CMEK_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); + TEST_SECRET_WITH_ROTATION_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); + TEST_SECRET_WITH_TOPIC_TO_CREATE_NAME = SecretName.of(PROJECT_ID, randomSecretId()); TEST_SECRET_WITH_EXPIRATION = createSecret(false); + TEST_SECRET_WITH_ROTATION = createSecret(false); TEST_SECRET_VERSION = addSecretVersion(TEST_SECRET_WITH_VERSIONS); TEST_SECRET_VERSION_TO_DESTROY = addSecretVersion(TEST_SECRET_WITH_VERSIONS); @@ -181,6 +190,9 @@ public static void afterAll() throws Exception { deleteSecret(TEST_SECRET_TO_DELAYED_DESTROY.getName()); deleteSecret(TEST_SECRET_WITH_EXPIRATION_TO_CREATE_NAME.toString()); deleteSecret(TEST_SECRET_WITH_EXPIRATION.getName()); + deleteSecret(TEST_SECRET_WITH_ROTATION_TO_CREATE_NAME.toString()); + deleteSecret(TEST_SECRET_WITH_ROTATION.getName()); + deleteSecret(TEST_SECRET_WITH_TOPIC_TO_CREATE_NAME.toString()); deleteTags(); } @@ -733,4 +745,49 @@ public void testDeleteSecretExpiration() throws IOException { assertThat(stdOut.toString()).contains("Deleted expiration from secret"); assertThat(secret.hasExpireTime()).isFalse(); } + + @Test + public void testCreateSecretWithRotation() throws IOException { + SecretName name = TEST_SECRET_WITH_ROTATION_TO_CREATE_NAME; + Secret secret = CreateSecretWithRotation.createSecretWithRotation( + name.getProject(), name.getSecret(), 2592000, PUBSUB_TOPIC_NAME); + + assertThat(stdOut.toString()).contains("Created secret"); + assertThat(stdOut.toString()).contains("with rotation"); + assertThat(secret.hasRotation()).isTrue(); + assertThat(secret.getTopicsCount()).isGreaterThan(0); + } + + @Test + public void testUpdateSecretRotation() throws IOException { + SecretName name = SecretName.parse(TEST_SECRET_WITH_ROTATION.getName()); + Secret secret = UpdateSecretRotation.updateSecretRotation( + name.getProject(), name.getSecret(), 3600000, PUBSUB_TOPIC_NAME); + + assertThat(stdOut.toString()).contains("Updated secret"); + assertThat(stdOut.toString()).contains("with new rotation policy"); + assertThat(secret.hasRotation()).isTrue(); + assertThat(secret.getTopicsCount()).isGreaterThan(0); + } + + @Test + public void testDeleteSecretRotation() throws IOException { + SecretName name = SecretName.parse(TEST_SECRET_WITH_ROTATION.getName()); + Secret secret = DeleteSecretRotation.deleteSecretRotation( + name.getProject(), name.getSecret()); + + assertThat(stdOut.toString()).contains("Deleted rotation from secret"); + assertThat(secret.hasRotation()).isFalse(); + } + + @Test + public void testCreateSecretWithTopic() throws IOException { + SecretName name = TEST_SECRET_WITH_TOPIC_TO_CREATE_NAME; + Secret secret = CreateSecretWithTopic.createSecretWithTopic( + name.getProject(), name.getSecret(), PUBSUB_TOPIC_NAME); + + assertThat(stdOut.toString()).contains("Created secret"); + assertThat(stdOut.toString()).contains("with topic"); + assertThat(secret.getTopicsCount()).isGreaterThan(0); + } } diff --git a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java index 0a20ebe4941..c9a9239f628 100644 --- a/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java +++ b/secretmanager/src/test/java/secretmanager/regionalsamples/SnippetsIT.java @@ -86,6 +86,7 @@ public class SnippetsIT { private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); private static final String REGIONAL_KMS_KEY_NAME = System.getenv("GOOGLE_CLOUD_REGIONAL_KMS_KEY"); + private static final String PUBSUB_TOPIC_NAME = System.getenv("GOOGLE_CLOUD_PUBSUB_TOPIC"); private static final String LABEL_KEY = "examplelabelkey"; private static final String LABEL_VALUE = "examplelabelvalue"; private static final String UPDATED_LABEL_KEY = "updatedlabelkey"; @@ -105,8 +106,11 @@ public class SnippetsIT { private static Secret TEST_REGIONAL_SECRET_WITH_VERSIONS; private static Secret TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY; private static Secret TEST_REGIONAL_SECRET_WITH_EXPIRATION; + private static Secret TEST_REGIONAL_SECRET_WITH_ROTATION; private static SecretName TEST_REGIONAL_SECRET_WITH_DELAYED_DESTROY; private static SecretName TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME; + private static SecretName TEST_REGIONAL_SECRET_WITH_ROTATION_TO_CREATE_NAME; + private static SecretName TEST_REGIONAL_SECRET_WITH_TOPIC_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_WITH_LABEL_TO_CREATE_NAME; private static SecretName TEST_REGIONAL_SECRET_WITH_TAGS_TO_CREATE_NAME; @@ -132,6 +136,8 @@ public static void beforeAll() throws Exception { Strings.isNullOrEmpty(LOCATION_ID)); Assert.assertFalse("missing REGIONAL_KMS_KEY_NAME", Strings.isNullOrEmpty(REGIONAL_KMS_KEY_NAME)); + Assert.assertFalse("missing GOOGLE_CLOUD_PUBSUB_TOPIC", + Strings.isNullOrEmpty(PUBSUB_TOPIC_NAME)); TEST_REGIONAL_SECRET = createRegionalSecret(); TEST_REGIONAL_SECRET_TO_DELETE = createRegionalSecret(); @@ -154,7 +160,12 @@ public static void beforeAll() throws Exception { SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME = SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); + TEST_REGIONAL_SECRET_WITH_ROTATION_TO_CREATE_NAME = + SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); + TEST_REGIONAL_SECRET_WITH_TOPIC_TO_CREATE_NAME = + SecretName.ofProjectLocationSecretName(PROJECT_ID, LOCATION_ID, randomSecretId()); TEST_REGIONAL_SECRET_WITH_EXPIRATION = createRegionalSecret(); + TEST_REGIONAL_SECRET_WITH_ROTATION = createRegionalSecret(); TEST_REGIONAL_SECRET_VERSION = addRegionalSecretVersion(TEST_REGIONAL_SECRET_WITH_VERSIONS); TEST_REGIONAL_SECRET_VERSION_TO_DESTROY = addRegionalSecretVersion(TEST_REGIONAL_SECRET_WITH_VERSIONS); @@ -204,6 +215,9 @@ public static void afterAll() throws Exception { deleteRegionalSecret(TEST_REGIONAL_SECRET_TO_DELAYED_DESTROY.getName()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_EXPIRATION_TO_CREATE_NAME.toString()); deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_EXPIRATION.getName()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_ROTATION_TO_CREATE_NAME.toString()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_ROTATION.getName()); + deleteRegionalSecret(TEST_REGIONAL_SECRET_WITH_TOPIC_TO_CREATE_NAME.toString()); deleteTags(); } @@ -821,5 +835,50 @@ public void testDeleteRegionalSecretExpiration() throws IOException { assertThat(stdOut.toString()).contains("Deleted expiration from secret"); assertThat(secret.hasExpireTime()).isFalse(); } + + @Test + public void testCreateRegionalSecretWithRotation() throws IOException { + SecretName name = TEST_REGIONAL_SECRET_WITH_ROTATION_TO_CREATE_NAME; + Secret secret = CreateRegionalSecretWithRotation.createRegionalSecretWithRotation( + name.getProject(), name.getLocation(), name.getSecret(), 2592000, PUBSUB_TOPIC_NAME); + + assertThat(stdOut.toString()).contains("Created secret"); + assertThat(stdOut.toString()).contains("with rotation"); + assertThat(secret.hasRotation()).isTrue(); + assertThat(secret.getTopicsCount()).isGreaterThan(0); + } + + @Test + public void testUpdateRegionalSecretRotation() throws IOException { + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET_WITH_ROTATION.getName()); + Secret secret = UpdateRegionalSecretRotation.updateRegionalSecretRotation( + name.getProject(), name.getLocation(), name.getSecret(), 3600000, PUBSUB_TOPIC_NAME); + + assertThat(stdOut.toString()).contains("Updated secret"); + assertThat(stdOut.toString()).contains("with new rotation policy"); + assertThat(secret.hasRotation()).isTrue(); + assertThat(secret.getTopicsCount()).isGreaterThan(0); + } + + @Test + public void testDeleteRegionalSecretRotation() throws IOException { + SecretName name = SecretName.parse(TEST_REGIONAL_SECRET_WITH_ROTATION.getName()); + Secret secret = DeleteRegionalSecretRotation.deleteRegionalSecretRotation( + name.getProject(), name.getLocation(), name.getSecret()); + + assertThat(stdOut.toString()).contains("Deleted rotation from secret"); + assertThat(secret.hasRotation()).isFalse(); + } + + @Test + public void testCreateRegionalSecretWithTopic() throws IOException { + SecretName name = TEST_REGIONAL_SECRET_WITH_TOPIC_TO_CREATE_NAME; + Secret secret = CreateRegionalSecretWithTopic.createRegionalSecretWithTopic( + name.getProject(), name.getLocation(), name.getSecret(), PUBSUB_TOPIC_NAME); + + assertThat(stdOut.toString()).contains("Created secret"); + assertThat(stdOut.toString()).contains("with topic"); + assertThat(secret.getTopicsCount()).isGreaterThan(0); + } }