Skip to content

feat(secretmanager): Add Cloud SQL managed-rotation samples - #2335

Draft
suvidha-malaviya wants to merge 2 commits into
GoogleCloudPlatform:mainfrom
suvidha-malaviya:feat/secretmanager-cloudsql-managed-rotation
Draft

suvidha-malaviya wants to merge 2 commits into
GoogleCloudPlatform:mainfrom
suvidha-malaviya:feat/secretmanager-cloudsql-managed-rotation

Conversation

@suvidha-malaviya

@suvidha-malaviya suvidha-malaviya commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Regional (Cloud SQL managed rotation):

  • create_regional_secret_with_cloud_sql_credentials — creates a secret restricted to the CLOUD_SQL_DB_CREDENTIALS type
  • enable_regional_secret_managed_rotation — links the secret to a Cloud SQL instance/user, creates version 1
  • rotate_regional_secret — triggers an on-demand rotation
  • update_regional_secret_with_managed_rotation_schedule — reconfigures the recurring rotation schedule on a secret that already has managed rotation enabled
  • get_regional_secret_type — reads back a regional secret's secret type

Global (secret-type restriction, not specific to Cloud SQL):

  • create_secret_with_type — creates a secret restricted to a given secret type (e.g. ACCESS_KEY, CERTIFICATE, OTHER_DB_CREDENTIALS, OTHER; CLOUD_SQL_DB_CREDENTIALS is reserved for regional secrets going through managed rotation)
  • get_secret_type — reads back a secret's secret type

Test coverage added for all seven samples in regionalsecretmanagerTest.php and secretmanagerTest.php. The Cloud SQL fixtures (testEnableRegionalSecretManagedRotation, testRotateRegionalSecret, testUpdateRegionalSecretWithManagedRotationSchedule) each grant roles/cloudsql.admin to their own freshly-created secret's principal before running, and revoke it again in teardown, since this grant is per-secret with no wildcard mechanism.

Bumps google/cloud-secret-manager to ^2.4.0, the minimum version with Cloud SQL managed-rotation support.

Additional test-project requirements:

  • Cloud SQL Admin API enabled (sqladmin.googleapis.com)
  • A pre-provisioned Cloud SQL instance + DB user, referenced via CLOUD_SQL_INSTANCE / CLOUD_SQL_USER env vars
  • The identity running these tests needs resourcemanager.projects.getIamPolicy/setIamPolicy on the test project (e.g. roles/resourcemanager.projectIamAdmin), in addition to Secret Manager and Cloud SQL permissions already required

@suvidha-malaviya
suvidha-malaviya requested review from a team as code owners September 28, 2026 12:31
@snippet-bot

snippet-bot Bot commented Sep 28, 2026

Copy link
Copy Markdown

Here is the summary of changes.

You are about to add 7 region tags.

This comment is generated by snippet-bot.
If you find problems with this result, please file an issue at:
https://github.com/googleapis/repo-automation-bots/issues.
To update this comment, add snippet-bot:force-run label or use the checkbox below:

  • Refresh this comment

@product-auto-label product-auto-label Bot added api: secretmanager Issues related to the Secret Manager API. samples Issues that are directly related to samples. labels Sep 28, 2026
@suvidha-malaviya
suvidha-malaviya marked this pull request as draft September 28, 2026 12:32

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new PHP samples and integration tests for Secret Manager regional and global secret types, specifically focusing on Cloud SQL managed rotation. It also adds a comprehensive testing guide in TESTING_cloudsql_managed_rotation.md and updates composer.json dependencies. The feedback highlights opportunities to improve test robustness and prevent resource leaks. Specifically, it is recommended to use PHPUnit's @Depends annotations to explicitly declare execution order for tests that rely on shared state, and to move the grantCloudSqlRole calls inside the try blocks so that the finally blocks are guaranteed to clean up and delete secrets even if the IAM grant fails.

}
}

public function testGetRegionalSecretType()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The test testGetRegionalSecretType implicitly depends on testCreateSecretWithCloudSqlCredentials having already run to create the secret self::$testSecretCloudSqlToCreateName. Relying on the declaration order of tests can lead to flaky or failing tests if PHPUnit is configured to run tests in a different order (e.g., using --order-by or in parallel). Adding a @depends annotation explicitly declares this dependency, ensuring correct execution order and skipping the dependent test if the parent test fails.

    /**
     * @depends testCreateSecretWithCloudSqlCredentials
     */
    public function testGetRegionalSecretType()

$this->assertSame(SecretType::ACCESS_KEY, $secret->getSecretType());
}

public function testGetSecretType()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The test testGetSecretType implicitly depends on testCreateSecretWithType having already run to create the secret self::$testSecretWithTypeToCreateName. Relying on the declaration order of tests can lead to flaky or failing tests if PHPUnit is configured to run tests in a different order. Adding a @depends annotation explicitly declares this dependency, ensuring correct execution order and skipping the dependent test if the parent test fails.

    /**
     * @depends testCreateSecretWithType
     */
    public function testGetSecretType()

Comment on lines +1110 to +1115
$secret = self::createCloudSqlCredentialsSecret();
$member = $secret->getPolicyMember()->getIamPolicyUidPrincipal();
self::grantCloudSqlRole($member);

try {
$name = self::$client->parseName($secret->getName());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If self::grantCloudSqlRole($member) throws an exception (for example, due to API rate limits, network issues, or transient IAM errors), the execution will halt before entering the try block. As a result, the newly created secret $secret will never be deleted, leading to orphaned resources in the GCP project. To prevent resource leaks, grantCloudSqlRole should be moved inside the try block so that the finally block is guaranteed to run and clean up the secret.

        $secret = self::createCloudSqlCredentialsSecret();
        $member = $secret->getPolicyMember()->getIamPolicyUidPrincipal();

        try {
            self::grantCloudSqlRole($member);
            $name = self::$client->parseName($secret->getName());

Comment on lines +1138 to +1143
$secret = self::createCloudSqlCredentialsSecret();
$member = $secret->getPolicyMember()->getIamPolicyUidPrincipal();
self::grantCloudSqlRole($member);

try {
$name = self::$client->parseName($secret->getName());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If self::grantCloudSqlRole($member) throws an exception, the execution will halt before entering the try block, leaking the newly created secret. Moving grantCloudSqlRole inside the try block ensures that the finally block always runs to clean up the secret.

        $secret = self::createCloudSqlCredentialsSecret();
        $member = $secret->getPolicyMember()->getIamPolicyUidPrincipal();

        try {
            self::grantCloudSqlRole($member);
            $name = self::$client->parseName($secret->getName());

Comment on lines +1172 to +1177
$secret = self::createCloudSqlCredentialsSecret();
$member = $secret->getPolicyMember()->getIamPolicyUidPrincipal();
self::grantCloudSqlRole($member);

try {
$name = self::$client->parseName($secret->getName());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If self::grantCloudSqlRole($member) throws an exception, the execution will halt before entering the try block, leaking the newly created secret. Moving grantCloudSqlRole inside the try block ensures that the finally block always runs to clean up the secret.

        $secret = self::createCloudSqlCredentialsSecret();
        $member = $secret->getPolicyMember()->getIamPolicyUidPrincipal();

        try {
            self::grantCloudSqlRole($member);
            $name = self::$client->parseName($secret->getName());

…amples

Adds Cloud SQL managed-rotation samples for regional secrets
(create/enable/rotate/schedule/get-type) plus secret-type samples for
global secrets (create-with-type/get-type), ported from the completed
Python reference implementation. Bumps google/cloud-secret-manager to
^2.4.0, the minimum version with Cloud SQL managed-rotation support.
@suvidha-malaviya
suvidha-malaviya force-pushed the feat/secretmanager-cloudsql-managed-rotation branch from 9e79149 to d655ae6 Compare September 28, 2026 12:37
- Add @Depends annotations so testGetRegionalSecretType/testGetSecretType
  explicitly declare their dependency on the test that creates their
  secret, instead of relying on declaration order.
- Move grantCloudSqlRole() inside the try block in the three Cloud SQL
  rotation tests so the secret is still cleaned up in finally if the
  grant itself throws.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: secretmanager Issues related to the Secret Manager API. samples Issues that are directly related to samples.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant