From 822fb3308bb02f8c6c9a2feae3ec3e586b3c14c2 Mon Sep 17 00:00:00 2001 From: durgesh-ninave-crest Date: Tue, 22 Jul 2025 15:01:26 +0530 Subject: [PATCH 1/3] chore(secretmanager): Added samples for delayed destroy --- .../create_secret_with_delayed_destroy.go | 68 ++++++++++++++++++ .../disable_secret_delayed_destroy.go | 61 ++++++++++++++++ ...te_regional_secret_with_delayed_destroy.go | 68 ++++++++++++++++++ ...disable_regional_secret_delayed_destroy.go | 67 +++++++++++++++++ .../regional_secretmanager_test.go | 55 +++++++++++++- ...te_regional_secret_with_delayed_destroy.go | 71 +++++++++++++++++++ secretmanager/secretmanager_test.go | 65 ++++++++++++++--- .../update_secret_with_delayed_destroy.go | 65 +++++++++++++++++ 8 files changed, 509 insertions(+), 11 deletions(-) create mode 100644 secretmanager/create_secret_with_delayed_destroy.go create mode 100644 secretmanager/disable_secret_delayed_destroy.go create mode 100644 secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go create mode 100644 secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go create mode 100644 secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go create mode 100644 secretmanager/update_secret_with_delayed_destroy.go diff --git a/secretmanager/create_secret_with_delayed_destroy.go b/secretmanager/create_secret_with_delayed_destroy.go new file mode 100644 index 0000000000..cb4083c550 --- /dev/null +++ b/secretmanager/create_secret_with_delayed_destroy.go @@ -0,0 +1,68 @@ +// Copyright 2025 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 +// +// https://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_delayed_destroy] +import ( + "context" + "fmt" + "io" + "time" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/protobuf/types/known/durationpb" +) + +// createSecretWithDelayedDestroy creates a new secret with the given name +// and version destroy ttl. A secret is a logical wrapper around a collection +// of secret versions. Secret versions hold the actual secret material. +func createSecretWithDelayedDestroy(w io.Writer, parent, secretId string, versionDestroyTtl int) error { + // parent := "projects/my-project" + // secretId := "my-secret" + // versionDestroyTtl := 86400 + + // Create the client. + ctx := context.Background() + client, err := secretmanager.NewClient(ctx) + if err != nil { + return fmt.Errorf("failed to create secretmanager client: %w", err) + } + defer client.Close() + + // Build the request. + req := &secretmanagerpb.CreateSecretRequest{ + Parent: parent, + SecretId: secretId, + Secret: &secretmanagerpb.Secret{ + Replication: &secretmanagerpb.Replication{ + Replication: &secretmanagerpb.Replication_Automatic_{ + Automatic: &secretmanagerpb.Replication_Automatic{}, + }, + }, + VersionDestroyTtl: durationpb.New(time.Duration(versionDestroyTtl) * time.Second), + }, + } + + // Call the API. + result, err := client.CreateSecret(ctx, req) + if err != nil { + return fmt.Errorf("failed to create secret: %w", err) + } + fmt.Fprintf(w, "Created secret with version destroy ttl: %s\n", result.Name) + return nil +} + +// [END secretmanager_create_secret_with_delayed_destroy] diff --git a/secretmanager/disable_secret_delayed_destroy.go b/secretmanager/disable_secret_delayed_destroy.go new file mode 100644 index 0000000000..4bb1f1cb53 --- /dev/null +++ b/secretmanager/disable_secret_delayed_destroy.go @@ -0,0 +1,61 @@ +// Copyright 2025 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 +// +// https://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_disable_secret_delayed_destroy] +import ( + "context" + "fmt" + "io" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/genproto/protobuf/field_mask" +) + +// disableSecretDelayedDestroy creates a new secret with the given name +// and version destroy ttl. A secret is a logical wrapper around a collection +// of secret versions. Secret versions hold the actual secret material. +func disableSecretDelayedDestroy(w io.Writer, name string) error { + // name := "projects/my-project/secrets/my-secret" + + // Create the client. + ctx := context.Background() + client, err := secretmanager.NewClient(ctx) + if err != nil { + return fmt.Errorf("failed to create secretmanager client: %w", err) + } + defer client.Close() + + // Build the request. + req := &secretmanagerpb.UpdateSecretRequest{ + Secret: &secretmanagerpb.Secret{ + Name: name, + }, + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"version_destroy_ttl"}, + }, + } + + // Call the API. + result, err := client.UpdateSecret(ctx, req) + if err != nil { + return fmt.Errorf("failed to update secret: %w", err) + } + fmt.Fprintf(w, "Updated secret: %s\n", result.Name) + return nil +} + +// [END secretmanager_disable_secret_delayed_destroy] diff --git a/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go b/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go new file mode 100644 index 0000000000..5d2a87cc18 --- /dev/null +++ b/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go @@ -0,0 +1,68 @@ +// Copyright 2025 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 +// +// https://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 regional_secretmanager + +// [START secretmanager_create_regional_secret_with_delayed_destroy] +import ( + "context" + "fmt" + "io" + "time" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/api/option" + "google.golang.org/protobuf/types/known/durationpb" +) + +// createRegionalSecretWithDelayedDestroy creates a new secret with the given name +// and version destroy ttl. A secret is a logical wrapper around a collection +// of secret versions. Secret versions hold the actual secret material. +func createRegionalSecretWithDelayedDestroy(w io.Writer, projectId, locationId, secretId string, versionDestroyTtl int) error { + // projectId := "my-project" + // locationId := "us-central1" + // secretId := "my-secret" + // versionDestroyTtl := 86400 + + // Create the client. + ctx := context.Background() + endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationId) + client, err := secretmanager.NewClient(ctx, option.WithEndpoint(endpoint)) + if err != nil { + return fmt.Errorf("failed to create secretmanager client: %w", err) + } + defer client.Close() + + parent := fmt.Sprintf("projects/%s/locations/%s", projectId, locationId) + + // Build the request. + req := &secretmanagerpb.CreateSecretRequest{ + Parent: parent, + SecretId: secretId, + Secret: &secretmanagerpb.Secret{ + VersionDestroyTtl: durationpb.New(time.Duration(versionDestroyTtl) * time.Second), + }, + } + + // Call the API. + result, err := client.CreateSecret(ctx, req) + if err != nil { + return fmt.Errorf("failed to create secret: %w", err) + } + fmt.Fprintf(w, "Created secret with version destroy ttl: %s\n", result.Name) + return nil +} + +// [END secretmanager_create_regional_secret_with_delayed_destroy] diff --git a/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go b/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go new file mode 100644 index 0000000000..304ffb3d0d --- /dev/null +++ b/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go @@ -0,0 +1,67 @@ +// Copyright 2025 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 +// +// https://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 regional_secretmanager + +// [START secretmanager_disable_regional_secret_delayed_destroy] +import ( + "context" + "fmt" + "io" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/api/option" + "google.golang.org/genproto/protobuf/field_mask" +) + +// disableRegionalSecretDelayedDestroy creates a new secret with the given name +// and version destroy ttl. A secret is a logical wrapper around a collection +// of secret versions. Secret versions hold the actual secret material. +func disableRegionalSecretDelayedDestroy(w io.Writer, projectId, locationId, secretId string) error { + // projectId := "my-project" + // locationId := "us-central1" + // secretId := "my-secret" + + // Create the client. + ctx := context.Background() + endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationId) + client, err := secretmanager.NewClient(ctx, option.WithEndpoint(endpoint)) + if err != nil { + return fmt.Errorf("failed to create secretmanager client: %w", err) + } + defer client.Close() + + name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", projectId, locationId, secretId) + + // Build the request. + req := &secretmanagerpb.UpdateSecretRequest{ + Secret: &secretmanagerpb.Secret{ + Name: name, + }, + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"version_destroy_ttl"}, + }, + } + + // Call the API. + result, err := client.UpdateSecret(ctx, req) + if err != nil { + return fmt.Errorf("failed to update secret: %w", err) + } + fmt.Fprintf(w, "Updated secret: %s\n", result.Name) + return nil +} + +// [END secretmanager_disable_regional_secret_delayed_destroy] diff --git a/secretmanager/regional_samples/regional_secretmanager_test.go b/secretmanager/regional_samples/regional_secretmanager_test.go index 0f41e74ed7..14c624f42c 100644 --- a/secretmanager/regional_samples/regional_secretmanager_test.go +++ b/secretmanager/regional_samples/regional_secretmanager_test.go @@ -33,9 +33,7 @@ import ( "github.com/gofrs/uuid" "google.golang.org/api/option" "google.golang.org/grpc/codes" - grpccodes "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - grpcstatus "google.golang.org/grpc/status" ) func testLocation(tb testing.TB) string { @@ -110,7 +108,7 @@ func testCleanupRegionalSecret(tb testing.TB, name string) { if err := client.DeleteSecret(ctx, &secretmanagerpb.DeleteSecretRequest{ Name: name, }); err != nil { - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { tb.Fatalf("testCleanupSecret: failed to delete regional secret: %v", err) } } @@ -481,3 +479,54 @@ func TestCreateRegionalSecretWithTags(t *testing.T) { t.Errorf("createRegionalSecretWithTags: expected %q to contain %q", got, want) } } + +func TestCreateRegionalSecretWithDelayedDestroy(t *testing.T) { + tc := testutil.SystemTest(t) + + secretID := testName(t) + locationID := testLocation(t) + + var b bytes.Buffer + if err := createRegionalSecretWithDelayedDestroy(&b, tc.ProjectID, locationID, secretID, 86400); err != nil { + t.Fatal(err) + } + defer testCleanupRegionalSecret(t, fmt.Sprintf("projects/%s/locations/%s/secrets/%s", tc.ProjectID, locationID, secretID)) + + if got, want := b.String(), "Created secret with version destroy ttl:"; !strings.Contains(got, want) { + t.Errorf("createSecret: expected %q to contain %q", got, want) + } +} + +func TestUpdateRegionalSecretWithDelayedDestroy(t *testing.T) { + tc := testutil.SystemTest(t) + + secret, secretID := testRegionalSecret(t, tc.ProjectID) + locationID := testLocation(t) + + var b bytes.Buffer + if err := updateRegionalSecretWithDelayedDestroy(&b, tc.ProjectID, locationID, secretID, 86400); err != nil { + t.Fatal(err) + } + defer testCleanupRegionalSecret(t, secret.Name) + + if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { + t.Errorf("createSecret: expected %q to contain %q", got, want) + } +} + +func TestDisableRegionalSecretDelayedDestroy(t *testing.T) { + tc := testutil.SystemTest(t) + + secret, secretID := testRegionalSecret(t, tc.ProjectID) + locationID := testLocation(t) + + var b bytes.Buffer + if err := disableRegionalSecretDelayedDestroy(&b, tc.ProjectID, locationID, secretID); err != nil { + t.Fatal(err) + } + defer testCleanupRegionalSecret(t, secret.Name) + + if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { + t.Errorf("createSecret: expected %q to contain %q", got, want) + } +} diff --git a/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go b/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go new file mode 100644 index 0000000000..18a7cf0d4a --- /dev/null +++ b/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go @@ -0,0 +1,71 @@ +// Copyright 2025 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 +// +// https://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 regional_secretmanager + +// [START secretmanager_update_regional_secret_with_delayed_destroy] +import ( + "context" + "fmt" + "io" + "time" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/api/option" + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/protobuf/types/known/durationpb" +) + +// updateRegionalSecretWithDelayedDestroy creates a new secret with the given name +// and version destroy ttl. A secret is a logical wrapper around a collection +// of secret versions. Secret versions hold the actual secret material. +func updateRegionalSecretWithDelayedDestroy(w io.Writer, projectId, locationId, secretId string, versionDestroyTtl int) error { + // projectId := "my-project" + // locationId := "us-central1" + // secretId := "my-secret" + // versionDestroyTtl := 86400 + + // Create the client. + ctx := context.Background() + endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationId) + client, err := secretmanager.NewClient(ctx, option.WithEndpoint(endpoint)) + if err != nil { + return fmt.Errorf("failed to create secretmanager client: %w", err) + } + defer client.Close() + + name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", projectId, locationId, secretId) + + // Build the request. + req := &secretmanagerpb.UpdateSecretRequest{ + Secret: &secretmanagerpb.Secret{ + Name: name, + VersionDestroyTtl: durationpb.New(time.Duration(versionDestroyTtl) * time.Second), + }, + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"version_destroy_ttl"}, + }, + } + + // Call the API. + result, err := client.UpdateSecret(ctx, req) + if err != nil { + return fmt.Errorf("failed to update secret: %w", err) + } + fmt.Fprintf(w, "Updated secret: %s\n", result.Name) + return nil +} + +// [END secretmanager_update_regional_secret_with_delayed_destroy] diff --git a/secretmanager/secretmanager_test.go b/secretmanager/secretmanager_test.go index 3477b04f94..127516e50a 100644 --- a/secretmanager/secretmanager_test.go +++ b/secretmanager/secretmanager_test.go @@ -34,9 +34,7 @@ import ( "github.com/gofrs/uuid" "google.golang.org/api/option" "google.golang.org/grpc/codes" - grpccodes "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - grpcstatus "google.golang.org/grpc/status" ) func testLocation(tb testing.TB) string { @@ -210,7 +208,7 @@ func testCleanupSecret(tb testing.TB, name string) { if err := client.DeleteSecret(ctx, &secretmanagerpb.DeleteSecretRequest{ Name: name, }); err != nil { - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { tb.Fatalf("testCleanupSecret: failed to delete secret: %v", err) } } @@ -224,7 +222,7 @@ func testCleanupRegionalSecret(tb testing.TB, name string) { if err := client.DeleteSecret(ctx, &secretmanagerpb.DeleteSecretRequest{ Name: name, }); err != nil { - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { tb.Fatalf("testCleanupSecret: failed to delete regional secret: %v", err) } } @@ -456,7 +454,7 @@ func TestDeleteSecret(t *testing.T) { _, err := client.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{ Name: secret.Name, }) - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { t.Errorf("deleteSecret: expected %v to be not found", err) } } @@ -501,7 +499,7 @@ func TestDeleteRegionalSecret(t *testing.T) { _, err := client.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{ Name: secret.Name, }) - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { t.Errorf("deleteRegionalSecret: expected %v to be not found", err) } @@ -521,7 +519,7 @@ func TestDeleteSecretWithEtag(t *testing.T) { _, err := client.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{ Name: secret.Name, }) - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { t.Errorf("deleteSecret: expected %v to be not found", err) } } @@ -542,7 +540,7 @@ func TestDeleteRegionalSecretWithEtag(t *testing.T) { _, err := client.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{ Name: secret.Name, }) - if terr, ok := grpcstatus.FromError(err); !ok || terr.Code() != grpccodes.NotFound { + if terr, ok := status.FromError(err); !ok || terr.Code() != codes.NotFound { t.Errorf("deleteRegionalSecret: expected %v to be not found", err) } } @@ -1675,3 +1673,54 @@ func TestCreateSecretWithTags(t *testing.T) { } } + +func TestCreateSecretWithDelayedDestroy(t *testing.T) { + tc := testutil.SystemTest(t) + + secretID := testName(t) + parent := fmt.Sprintf("projects/%s", tc.ProjectID) + + var b bytes.Buffer + if err := createSecretWithDelayedDestroy(&b, parent, secretID, 86400); err != nil { + t.Fatal(err) + } + defer testCleanupSecret(t, fmt.Sprintf("projects/%s/secrets/%s", tc.ProjectID, secretID)) + + if got, want := b.String(), "Created secret with version destroy ttl:"; !strings.Contains(got, want) { + t.Errorf("createSecretWithDelayedDestroy: expected %q to contain %q", got, want) + } +} + +func TestUpdateSecretWithDelayedDestroy(t *testing.T) { + tc := testutil.SystemTest(t) + + secret := testSecret(t, tc.ProjectID) + secretID := secret.Name + + var b bytes.Buffer + if err := updateSecretWithDelayedDestroy(&b, secretID, 86400); err != nil { + t.Fatal(err) + } + defer testCleanupSecret(t, secretID) + + if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { + t.Errorf("createSecretWithDelayedDestroy: expected %q to contain %q", got, want) + } +} + +func TestDisableSecretDelayedDestroy(t *testing.T) { + tc := testutil.SystemTest(t) + + secret := testSecret(t, tc.ProjectID) + secretID := secret.Name + + var b bytes.Buffer + if err := disableSecretDelayedDestroy(&b, secretID); err != nil { + t.Fatal(err) + } + defer testCleanupSecret(t, secretID) + + if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { + t.Errorf("createSecretWithDelayedDestroy: expected %q to contain %q", got, want) + } +} diff --git a/secretmanager/update_secret_with_delayed_destroy.go b/secretmanager/update_secret_with_delayed_destroy.go new file mode 100644 index 0000000000..6173c2e732 --- /dev/null +++ b/secretmanager/update_secret_with_delayed_destroy.go @@ -0,0 +1,65 @@ +// Copyright 2025 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 +// +// https://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_with_delayed_destroy] +import ( + "context" + "fmt" + "io" + "time" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/protobuf/types/known/durationpb" +) + +// updateSecretWithDelayedDestroy creates a new secret with the given name +// and version destroy ttl. A secret is a logical wrapper around a collection +// of secret versions. Secret versions hold the actual secret material. +func updateSecretWithDelayedDestroy(w io.Writer, name string, versionDestroyTtl int) error { + // name := "projects/my-project/secrets/my-secret" + // versionDestroyTtl := 86400 + + // Create the client. + ctx := context.Background() + client, err := secretmanager.NewClient(ctx) + if err != nil { + return fmt.Errorf("failed to create secretmanager client: %w", err) + } + defer client.Close() + + // Build the request. + req := &secretmanagerpb.UpdateSecretRequest{ + Secret: &secretmanagerpb.Secret{ + Name: name, + VersionDestroyTtl: durationpb.New(time.Duration(versionDestroyTtl) * time.Second), + }, + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"version_destroy_ttl"}, + }, + } + + // Call the API. + result, err := client.UpdateSecret(ctx, req) + if err != nil { + return fmt.Errorf("failed to update secret: %w", err) + } + fmt.Fprintf(w, "Updated secret: %s\n", result.Name) + return nil +} + +// [END secretmanager_update_secret_with_delayed_destroy] From f690b50fd848cd593e586d55168fc2ca6e3f7328 Mon Sep 17 00:00:00 2001 From: durgesh-ninave-crest Date: Tue, 22 Jul 2025 15:19:18 +0530 Subject: [PATCH 2/3] chore(secretmanager): address gemini review comments --- .../create_secret_with_delayed_destroy.go | 6 +++--- .../disable_secret_delayed_destroy.go | 6 +++--- ...ate_regional_secret_with_delayed_destroy.go | 14 +++++++------- .../disable_regional_secret_delayed_destroy.go | 18 +++++++++--------- .../regional_secretmanager_test.go | 6 +++--- ...ate_regional_secret_with_delayed_destroy.go | 17 ++++++++--------- secretmanager/secretmanager_test.go | 4 ++-- .../update_secret_with_delayed_destroy.go | 5 ++--- 8 files changed, 37 insertions(+), 39 deletions(-) diff --git a/secretmanager/create_secret_with_delayed_destroy.go b/secretmanager/create_secret_with_delayed_destroy.go index cb4083c550..86b621a29e 100644 --- a/secretmanager/create_secret_with_delayed_destroy.go +++ b/secretmanager/create_secret_with_delayed_destroy.go @@ -29,9 +29,9 @@ import ( // createSecretWithDelayedDestroy creates a new secret with the given name // and version destroy ttl. A secret is a logical wrapper around a collection // of secret versions. Secret versions hold the actual secret material. -func createSecretWithDelayedDestroy(w io.Writer, parent, secretId string, versionDestroyTtl int) error { +func createSecretWithDelayedDestroy(w io.Writer, parent, secretID string, versionDestroyTtl int) error { // parent := "projects/my-project" - // secretId := "my-secret" + // secretID := "my-secret" // versionDestroyTtl := 86400 // Create the client. @@ -45,7 +45,7 @@ func createSecretWithDelayedDestroy(w io.Writer, parent, secretId string, versio // Build the request. req := &secretmanagerpb.CreateSecretRequest{ Parent: parent, - SecretId: secretId, + SecretId: secretID, Secret: &secretmanagerpb.Secret{ Replication: &secretmanagerpb.Replication{ Replication: &secretmanagerpb.Replication_Automatic_{ diff --git a/secretmanager/disable_secret_delayed_destroy.go b/secretmanager/disable_secret_delayed_destroy.go index 4bb1f1cb53..4dcede0584 100644 --- a/secretmanager/disable_secret_delayed_destroy.go +++ b/secretmanager/disable_secret_delayed_destroy.go @@ -25,9 +25,9 @@ import ( "google.golang.org/genproto/protobuf/field_mask" ) -// disableSecretDelayedDestroy creates a new secret with the given name -// and version destroy ttl. A secret is a logical wrapper around a collection -// of secret versions. Secret versions hold the actual secret material. +// disableSecretDelayedDestroy disables the delayed destroy configuration on an +// existing secret. When disabled, secret versions are destroyed immediately +// upon deletion. func disableSecretDelayedDestroy(w io.Writer, name string) error { // name := "projects/my-project/secrets/my-secret" diff --git a/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go b/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go index 5d2a87cc18..03fd56a169 100644 --- a/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go +++ b/secretmanager/regional_samples/create_regional_secret_with_delayed_destroy.go @@ -30,27 +30,27 @@ import ( // createRegionalSecretWithDelayedDestroy creates a new secret with the given name // and version destroy ttl. A secret is a logical wrapper around a collection // of secret versions. Secret versions hold the actual secret material. -func createRegionalSecretWithDelayedDestroy(w io.Writer, projectId, locationId, secretId string, versionDestroyTtl int) error { - // projectId := "my-project" - // locationId := "us-central1" - // secretId := "my-secret" +func createRegionalSecretWithDelayedDestroy(w io.Writer, projectID, locationID, secretID string, versionDestroyTtl int) error { + // projectID := "my-project" + // locationID := "us-central1" + // secretID := "my-secret" // versionDestroyTtl := 86400 // Create the client. ctx := context.Background() - endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationId) + endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationID) client, err := secretmanager.NewClient(ctx, option.WithEndpoint(endpoint)) if err != nil { return fmt.Errorf("failed to create secretmanager client: %w", err) } defer client.Close() - parent := fmt.Sprintf("projects/%s/locations/%s", projectId, locationId) + parent := fmt.Sprintf("projects/%s/locations/%s", projectID, locationID) // Build the request. req := &secretmanagerpb.CreateSecretRequest{ Parent: parent, - SecretId: secretId, + SecretId: secretID, Secret: &secretmanagerpb.Secret{ VersionDestroyTtl: durationpb.New(time.Duration(versionDestroyTtl) * time.Second), }, diff --git a/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go b/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go index 304ffb3d0d..e61bff3c4a 100644 --- a/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go +++ b/secretmanager/regional_samples/disable_regional_secret_delayed_destroy.go @@ -26,24 +26,24 @@ import ( "google.golang.org/genproto/protobuf/field_mask" ) -// disableRegionalSecretDelayedDestroy creates a new secret with the given name -// and version destroy ttl. A secret is a logical wrapper around a collection -// of secret versions. Secret versions hold the actual secret material. -func disableRegionalSecretDelayedDestroy(w io.Writer, projectId, locationId, secretId string) error { - // projectId := "my-project" - // locationId := "us-central1" - // secretId := "my-secret" +// disableRegionalSecretDelayedDestroy disables the delayed destroy configuration on an +// existing regional secret. When disabled, secret versions are destroyed +// immediately upon deletion. +func disableRegionalSecretDelayedDestroy(w io.Writer, projectID, locationID, secretID string) error { + // projectID := "my-project" + // locationID := "us-central1" + // secretID := "my-secret" // Create the client. ctx := context.Background() - endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationId) + endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationID) client, err := secretmanager.NewClient(ctx, option.WithEndpoint(endpoint)) if err != nil { return fmt.Errorf("failed to create secretmanager client: %w", err) } defer client.Close() - name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", projectId, locationId, secretId) + name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", projectID, locationID, secretID) // Build the request. req := &secretmanagerpb.UpdateSecretRequest{ diff --git a/secretmanager/regional_samples/regional_secretmanager_test.go b/secretmanager/regional_samples/regional_secretmanager_test.go index 14c624f42c..7642c06f70 100644 --- a/secretmanager/regional_samples/regional_secretmanager_test.go +++ b/secretmanager/regional_samples/regional_secretmanager_test.go @@ -493,7 +493,7 @@ func TestCreateRegionalSecretWithDelayedDestroy(t *testing.T) { defer testCleanupRegionalSecret(t, fmt.Sprintf("projects/%s/locations/%s/secrets/%s", tc.ProjectID, locationID, secretID)) if got, want := b.String(), "Created secret with version destroy ttl:"; !strings.Contains(got, want) { - t.Errorf("createSecret: expected %q to contain %q", got, want) + t.Errorf("createRegionalSecretWithDelayedDestroy: expected %q to contain %q", got, want) } } @@ -510,7 +510,7 @@ func TestUpdateRegionalSecretWithDelayedDestroy(t *testing.T) { defer testCleanupRegionalSecret(t, secret.Name) if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { - t.Errorf("createSecret: expected %q to contain %q", got, want) + t.Errorf("updateRegionalSecretWithDelayedDestroy: expected %q to contain %q", got, want) } } @@ -527,6 +527,6 @@ func TestDisableRegionalSecretDelayedDestroy(t *testing.T) { defer testCleanupRegionalSecret(t, secret.Name) if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { - t.Errorf("createSecret: expected %q to contain %q", got, want) + t.Errorf("disableRegionalSecretDelayedDestroy: expected %q to contain %q", got, want) } } diff --git a/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go b/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go index 18a7cf0d4a..9edc59779e 100644 --- a/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go +++ b/secretmanager/regional_samples/update_regional_secret_with_delayed_destroy.go @@ -28,25 +28,24 @@ import ( "google.golang.org/protobuf/types/known/durationpb" ) -// updateRegionalSecretWithDelayedDestroy creates a new secret with the given name -// and version destroy ttl. A secret is a logical wrapper around a collection -// of secret versions. Secret versions hold the actual secret material. -func updateRegionalSecretWithDelayedDestroy(w io.Writer, projectId, locationId, secretId string, versionDestroyTtl int) error { - // projectId := "my-project" - // locationId := "us-central1" - // secretId := "my-secret" +// updateRegionalSecretWithDelayedDestroy updates the version destroy TTL on an +// existing regional secret. +func updateRegionalSecretWithDelayedDestroy(w io.Writer, projectID, locationID, secretID string, versionDestroyTtl int) error { + // projectID := "my-project" + // locationID := "us-central1" + // secretID := "my-secret" // versionDestroyTtl := 86400 // Create the client. ctx := context.Background() - endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationId) + endpoint := fmt.Sprintf("secretmanager.%s.rep.googleapis.com:443", locationID) client, err := secretmanager.NewClient(ctx, option.WithEndpoint(endpoint)) if err != nil { return fmt.Errorf("failed to create secretmanager client: %w", err) } defer client.Close() - name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", projectId, locationId, secretId) + name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", projectID, locationID, secretID) // Build the request. req := &secretmanagerpb.UpdateSecretRequest{ diff --git a/secretmanager/secretmanager_test.go b/secretmanager/secretmanager_test.go index 127516e50a..3ea4542bfd 100644 --- a/secretmanager/secretmanager_test.go +++ b/secretmanager/secretmanager_test.go @@ -1704,7 +1704,7 @@ func TestUpdateSecretWithDelayedDestroy(t *testing.T) { defer testCleanupSecret(t, secretID) if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { - t.Errorf("createSecretWithDelayedDestroy: expected %q to contain %q", got, want) + t.Errorf("updateSecretWithDelayedDestroy: expected %q to contain %q", got, want) } } @@ -1721,6 +1721,6 @@ func TestDisableSecretDelayedDestroy(t *testing.T) { defer testCleanupSecret(t, secretID) if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { - t.Errorf("createSecretWithDelayedDestroy: expected %q to contain %q", got, want) + t.Errorf("disableSecretDelayedDestroy: expected %q to contain %q", got, want) } } diff --git a/secretmanager/update_secret_with_delayed_destroy.go b/secretmanager/update_secret_with_delayed_destroy.go index 6173c2e732..44c1726084 100644 --- a/secretmanager/update_secret_with_delayed_destroy.go +++ b/secretmanager/update_secret_with_delayed_destroy.go @@ -27,9 +27,8 @@ import ( "google.golang.org/protobuf/types/known/durationpb" ) -// updateSecretWithDelayedDestroy creates a new secret with the given name -// and version destroy ttl. A secret is a logical wrapper around a collection -// of secret versions. Secret versions hold the actual secret material. +// updateSecretWithDelayedDestroy updates the version destroy TTL on an +// existing secret. func updateSecretWithDelayedDestroy(w io.Writer, name string, versionDestroyTtl int) error { // name := "projects/my-project/secrets/my-secret" // versionDestroyTtl := 86400 From bf4b35b19463b63256704d23e2b3d6968bc998d3 Mon Sep 17 00:00:00 2001 From: durgesh-ninave-crest Date: Fri, 25 Jul 2025 17:36:54 +0530 Subject: [PATCH 3/3] chore(secretmanager): Updated test assertions --- .../regional_secretmanager_test.go | 36 ++++++++++++++++++- secretmanager/secretmanager_test.go | 36 ++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/secretmanager/regional_samples/regional_secretmanager_test.go b/secretmanager/regional_samples/regional_secretmanager_test.go index 7642c06f70..b624cb12d4 100644 --- a/secretmanager/regional_samples/regional_secretmanager_test.go +++ b/secretmanager/regional_samples/regional_secretmanager_test.go @@ -130,6 +130,20 @@ func TestCreateRegionalSecretWithLabels(t *testing.T) { } } +func testGetRegionalSecret(tb testing.TB, name string) *secretmanagerpb.Secret { + tb.Helper() + + client, ctx := testRegionalClient(tb) + + secret, err := client.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{ + Name: name, + }) + if err != nil { + tb.Fatalf("testGetRegionalSecret: failed to get secret: %v", err) + } + return secret +} + func TestDeleteRegionalSecretLabel(t *testing.T) { tc := testutil.SystemTest(t) @@ -490,11 +504,19 @@ func TestCreateRegionalSecretWithDelayedDestroy(t *testing.T) { if err := createRegionalSecretWithDelayedDestroy(&b, tc.ProjectID, locationID, secretID, 86400); err != nil { t.Fatal(err) } - defer testCleanupRegionalSecret(t, fmt.Sprintf("projects/%s/locations/%s/secrets/%s", tc.ProjectID, locationID, secretID)) + + name := fmt.Sprintf("projects/%s/locations/%s/secrets/%s", tc.ProjectID, locationID, secretID) + defer testCleanupRegionalSecret(t, name) if got, want := b.String(), "Created secret with version destroy ttl:"; !strings.Contains(got, want) { t.Errorf("createRegionalSecretWithDelayedDestroy: expected %q to contain %q", got, want) } + + secret := testGetRegionalSecret(t, name) + + if got, want := secret.VersionDestroyTtl.Seconds, int64(86400); got != want { + t.Errorf("createRegionalSecretWithDelayedDestroy: expected %v to be %v", got, want) + } } func TestUpdateRegionalSecretWithDelayedDestroy(t *testing.T) { @@ -512,6 +534,12 @@ func TestUpdateRegionalSecretWithDelayedDestroy(t *testing.T) { if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { t.Errorf("updateRegionalSecretWithDelayedDestroy: expected %q to contain %q", got, want) } + + updatedSecret := testGetRegionalSecret(t, secret.Name) + + if got, want := updatedSecret.VersionDestroyTtl.Seconds, int64(86400); got != want { + t.Errorf("updateRegionalSecretWithDelayedDestroy: expected %v to be %v", got, want) + } } func TestDisableRegionalSecretDelayedDestroy(t *testing.T) { @@ -529,4 +557,10 @@ func TestDisableRegionalSecretDelayedDestroy(t *testing.T) { if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { t.Errorf("disableRegionalSecretDelayedDestroy: expected %q to contain %q", got, want) } + + updatedSecret := testGetRegionalSecret(t, secret.Name) + + if updatedSecret.VersionDestroyTtl != nil { + t.Errorf("disableRegionalSecretDelayedDestroy: expected VersionDestroyTtl to be nil, got non-nil") + } } diff --git a/secretmanager/secretmanager_test.go b/secretmanager/secretmanager_test.go index 3ea4542bfd..ecf2cf1592 100644 --- a/secretmanager/secretmanager_test.go +++ b/secretmanager/secretmanager_test.go @@ -200,6 +200,20 @@ func testRegionalSecretVersion(tb testing.TB, parent string, payload []byte) *se return version } +func testGetSecret(tb testing.TB, name string) *secretmanagerpb.Secret { + tb.Helper() + + client, ctx := testClient(tb) + + secret, err := client.GetSecret(ctx, &secretmanagerpb.GetSecretRequest{ + Name: name, + }) + if err != nil { + tb.Fatalf("testGetSecret: failed to get secret: %v", err) + } + return secret +} + func testCleanupSecret(tb testing.TB, name string) { tb.Helper() @@ -1684,11 +1698,19 @@ func TestCreateSecretWithDelayedDestroy(t *testing.T) { if err := createSecretWithDelayedDestroy(&b, parent, secretID, 86400); err != nil { t.Fatal(err) } - defer testCleanupSecret(t, fmt.Sprintf("projects/%s/secrets/%s", tc.ProjectID, secretID)) + + name := fmt.Sprintf("projects/%s/secrets/%s", tc.ProjectID, secretID) + defer testCleanupSecret(t, name) if got, want := b.String(), "Created secret with version destroy ttl:"; !strings.Contains(got, want) { t.Errorf("createSecretWithDelayedDestroy: expected %q to contain %q", got, want) } + + secret := testGetSecret(t, name) + + if got, want := secret.VersionDestroyTtl.Seconds, int64(86400); got != want { + t.Errorf("createSecretWithDelayedDestroy: expected %v to be %v", got, want) + } } func TestUpdateSecretWithDelayedDestroy(t *testing.T) { @@ -1706,6 +1728,12 @@ func TestUpdateSecretWithDelayedDestroy(t *testing.T) { if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { t.Errorf("updateSecretWithDelayedDestroy: expected %q to contain %q", got, want) } + + updatedSecret := testGetSecret(t, secretID) + + if got, want := updatedSecret.VersionDestroyTtl.Seconds, int64(86400); got != want { + t.Errorf("updateSecretWithDelayedDestroy: expected %v to be %v", got, want) + } } func TestDisableSecretDelayedDestroy(t *testing.T) { @@ -1723,4 +1751,10 @@ func TestDisableSecretDelayedDestroy(t *testing.T) { if got, want := b.String(), "Updated secret:"; !strings.Contains(got, want) { t.Errorf("disableSecretDelayedDestroy: expected %q to contain %q", got, want) } + + updatedSecret := testGetSecret(t, secretID) + + if updatedSecret.VersionDestroyTtl != nil { + t.Errorf("disableSecretDelayedDestroy: expected VersionDestroyTtl to be nil, got non-nil") + } }