This is an automated email from the ASF dual-hosted git repository.

shunping pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new 6053b781a2c [Java] Move GCP-related secret classes and tests from 
sdks/java/core to google-cloud-platform-core (#40019)
6053b781a2c is described below

commit 6053b781a2cba1c274dbe7dd749bd389f7e1ab09
Author: Shunping Huang <[email protected]>
AuthorDate: Tue Sep 8 11:01:06 2026 -0400

    [Java] Move GCP-related secret classes and tests from sdks/java/core to 
google-cloud-platform-core (#40019)
---
 .../trigger_files/beam_PostCommit_XVR_Direct.json  |   2 +-
 .../trigger_files/beam_PostCommit_XVR_Flink.json   |   5 +-
 ...am_PostCommit_XVR_JavaUsingPython_Dataflow.json |   5 +-
 .../trigger_files/beam_PostCommit_XVR_Spark3.json  |   4 +-
 .../org/apache/beam/gradle/BeamModulePlugin.groovy |   1 +
 .../resources/beam/checkstyle/suppressions.xml     |   8 +-
 sdks/java/core/build.gradle                        |  13 --
 .../sdk/transforms/GroupByEncryptedKeyTest.java    | 153 +----------------
 .../apache/beam/sdk/transforms/GroupByKeyTest.java | 112 -------------
 .../java/org/apache/beam/sdk/util/SecretTest.java  | 161 ------------------
 .../apache/beam/sdk/util/TestSecretRegistrar.java} |   8 +-
 .../util/construction/ValidateRunnerXlangTest.java |  67 +-------
 .../google-cloud-platform-core/build.gradle        |   6 +
 .../gcp}/util/GcpHsmGeneratedSecret.java           |   8 +-
 .../gcp}/util/GcpHsmGeneratedSecretRegistrar.java  |   3 +-
 .../beam/sdk/extensions/gcp}/util/GcpSecret.java   |   3 +-
 .../extensions/gcp}/util/GcpSecretRegistrar.java   |   3 +-
 .../transforms/GcpGroupByEncryptedKeyTest.java}    | 130 ++++++++------
 .../gcp/transforms/GcpGroupByKeyIT.java}           |  11 +-
 .../gcp}/util/GcpSecretRegistrarTest.java          |   3 +-
 .../sdk/extensions/gcp/util/GcpSecretTest.java}    | 186 ++++-----------------
 sdks/java/io/components/build.gradle               |   3 +
 .../runners/portability/expansion_service_test.py  |   6 +
 23 files changed, 178 insertions(+), 723 deletions(-)

diff --git a/.github/trigger_files/beam_PostCommit_XVR_Direct.json 
b/.github/trigger_files/beam_PostCommit_XVR_Direct.json
index 3b864120bf9..c04f8e34f87 100644
--- a/.github/trigger_files/beam_PostCommit_XVR_Direct.json
+++ b/.github/trigger_files/beam_PostCommit_XVR_Direct.json
@@ -1,4 +1,4 @@
 {
-  "modification": 1,
+  "modification": 2,
   "https://github.com/apache/beam/pull/39990": "removing dead code from 
FnApiDoFnRunner"
 }
diff --git a/.github/trigger_files/beam_PostCommit_XVR_Flink.json 
b/.github/trigger_files/beam_PostCommit_XVR_Flink.json
index a60830fe7d2..57f49e9baef 100644
--- a/.github/trigger_files/beam_PostCommit_XVR_Flink.json
+++ b/.github/trigger_files/beam_PostCommit_XVR_Flink.json
@@ -1,5 +1,4 @@
 {
-  "modification": 3,
-  "trigger-2026-04-04": "portable_runner expand_sdf opt-in",
-  "https://github.com/apache/beam/pull/39990": "removing dead code from 
FnApiDoFnRunner"
+  "modification": 4,
+  "trigger-2026-04-04": "portable_runner expand_sdf opt-in"
 }
diff --git 
a/.github/trigger_files/beam_PostCommit_XVR_JavaUsingPython_Dataflow.json 
b/.github/trigger_files/beam_PostCommit_XVR_JavaUsingPython_Dataflow.json
index 0ca37f8c8e2..7ab7bcd9a9c 100644
--- a/.github/trigger_files/beam_PostCommit_XVR_JavaUsingPython_Dataflow.json
+++ b/.github/trigger_files/beam_PostCommit_XVR_JavaUsingPython_Dataflow.json
@@ -1,5 +1,4 @@
 {
-  "comment": "Modify this file in a trivial way to cause this test suite to 
run.",
-  "modification": 1,
-  "https://github.com/apache/beam/pull/39990": "removing dead code from 
FnApiDoFnRunner"
+    "comment": "Modify this file in a trivial way to cause this test suite to 
run.",
+    "modification": 2
 }
diff --git a/.github/trigger_files/beam_PostCommit_XVR_Spark3.json 
b/.github/trigger_files/beam_PostCommit_XVR_Spark3.json
index 74a5d652c7b..4fad3843d36 100644
--- a/.github/trigger_files/beam_PostCommit_XVR_Spark3.json
+++ b/.github/trigger_files/beam_PostCommit_XVR_Spark3.json
@@ -1,4 +1,4 @@
 {
-  "trigger-2026-07-08": "portable_runner expand_sdf opt-in 2",
-  "https://github.com/apache/beam/pull/39990": "removing dead code from 
FnApiDoFnRunner"
+  "modification": 1,
+  "trigger-2026-07-08": "portable_runner expand_sdf opt-in 2"
 }
diff --git 
a/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy 
b/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy
index da54354f01b..be10dd4779c 100644
--- a/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy
+++ b/buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy
@@ -803,6 +803,7 @@ class BeamModulePlugin implements Plugin<Project> {
         grpc_google_cloud_pubsub_v1                 : 
"com.google.api.grpc:grpc-google-cloud-pubsub-v1", // 
google_cloud_platform_libraries_bom sets version
         grpc_google_common_protos                   : 
"com.google.api.grpc:grpc-google-common-protos", // 
google_cloud_platform_libraries_bom sets version
         grpc_grpclb                                 : "io.grpc:grpc-grpclb", 
// google_cloud_platform_libraries_bom sets version
+        grpc_inprocess                              : 
"io.grpc:grpc-inprocess", // google_cloud_platform_libraries_bom sets version
         grpc_protobuf                               : "io.grpc:grpc-protobuf", 
// google_cloud_platform_libraries_bom sets version
         grpc_protobuf_lite                          : 
"io.grpc:grpc-protobuf-lite", // google_cloud_platform_libraries_bom sets 
version
         grpc_netty                                  : "io.grpc:grpc-netty", // 
google_cloud_platform_libraries_bom sets version
diff --git 
a/sdks/java/build-tools/src/main/resources/beam/checkstyle/suppressions.xml 
b/sdks/java/build-tools/src/main/resources/beam/checkstyle/suppressions.xml
index 76dffb30271..833fd30cf21 100644
--- a/sdks/java/build-tools/src/main/resources/beam/checkstyle/suppressions.xml
+++ b/sdks/java/build-tools/src/main/resources/beam/checkstyle/suppressions.xml
@@ -58,11 +58,9 @@
   <!-- gRPC/protobuf exceptions -->
   <!-- Non-vendored gRPC/protobuf imports are allowed for files that depend on 
libraries that expose gRPC/protobuf in its public API -->
   <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*extensions.*protobuf.*" />
-  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*core.*GcpHsmGeneratedSecret.*" />
-  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*core.*GroupByEncryptedKeyTest.*" />
-  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*core.*GroupByKeyTest.*" />
-  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*core.*GroupByKeyIT.*" />
-  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*core.*ValidateRunnerXlangTest.*" />
+  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*extensions.*gcp.*GcpHsmGeneratedSecret.*" />
+  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*extensions.*gcp.*GcpGroupByEncryptedKeyTest.*" />
+  <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*extensions.*gcp.*GcpGroupByKeyIT.*" />
   <suppress id="ForbidNonVendoredGrpcProtobuf" files=".*sdk.*extensions.*ml.*" 
/>
   <suppress id="ForbidNonVendoredGrpcProtobuf" 
files=".*sdk.*io.*components.*ratelimiter.*" />
   <suppress id="ForbidNonVendoredGrpcProtobuf" files=".*sdk.*io.*gcp.*" />
diff --git a/sdks/java/core/build.gradle b/sdks/java/core/build.gradle
index f532e9d1416..f95a8a53906 100644
--- a/sdks/java/core/build.gradle
+++ b/sdks/java/core/build.gradle
@@ -102,15 +102,6 @@ dependencies {
   shadow library.java.slf4j_api
   shadow library.java.snappy_java
   shadow library.java.joda_time
-  implementation 
enforcedPlatform(library.java.google_cloud_platform_libraries_bom)
-  implementation library.java.gax
-  implementation library.java.google_cloud_kms
-  implementation library.java.proto_google_cloud_kms_v1
-  implementation library.java.google_cloud_tink
-  implementation library.java.google_cloud_secret_manager
-  implementation library.java.proto_google_cloud_secret_manager_v1
-  implementation library.java.protobuf_java
-  permitUnusedDeclared 
enforcedPlatform(library.java.google_cloud_platform_libraries_bom)
   provided library.java.json_org
   implementation library.java.everit_json_schema
   implementation library.java.guava
@@ -133,10 +124,6 @@ dependencies {
   shadowTest library.java.log4j
   shadowTest library.java.log4j2_api
   shadowTest library.java.jamm
-  shadowTest enforcedPlatform(library.java.google_cloud_platform_libraries_bom)
-  shadowTest library.java.google_cloud_secret_manager
-  shadowTest library.java.google_cloud_kms
-  shadowTest library.java.google_cloud_tink
   testRuntimeOnly library.java.slf4j_jdk14
 }
 
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
index a929d62d29d..7bcebcef5b7 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
+++ 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
@@ -17,18 +17,11 @@
  */
 package org.apache.beam.sdk.transforms;
 
-import static org.junit.Assert.assertThrows;
-
-import com.google.cloud.secretmanager.v1.ProjectName;
-import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
-import com.google.cloud.secretmanager.v1.SecretName;
-import com.google.cloud.secretmanager.v1.SecretPayload;
-import com.google.protobuf.ByteString;
-import java.io.IOException;
 import java.io.Serializable;
 import java.nio.charset.Charset;
-import java.security.SecureRandom;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
@@ -39,14 +32,11 @@ import org.apache.beam.sdk.coders.VarIntCoder;
 import org.apache.beam.sdk.testing.NeedsRunner;
 import org.apache.beam.sdk.testing.PAssert;
 import org.apache.beam.sdk.testing.TestPipeline;
-import org.apache.beam.sdk.util.GcpHsmGeneratedSecret;
-import org.apache.beam.sdk.util.GcpSecret;
+import org.apache.beam.sdk.util.RawSecret;
 import org.apache.beam.sdk.util.Secret;
 import org.apache.beam.sdk.values.KV;
 import org.apache.beam.sdk.values.PCollection;
 import org.checkerframework.checker.nullness.qual.Nullable;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -100,138 +90,9 @@ public class GroupByEncryptedKeyTest implements 
Serializable {
     p.run();
   }
 
-  private static final String PROJECT_ID = "apache-beam-testing";
-  private static final String SECRET_ID = "gbek-test";
-  private static Secret gcpSecret;
-  private static Secret gcpHsmGeneratedSecret;
-  private static final String KEY_RING_ID = "gbek-test-key-ring";
-  private static final String KEY_ID = "gbek-test-key";
-
-  @BeforeClass
-  public static void setup() throws IOException {
-    SecretManagerServiceClient client = SecretManagerServiceClient.create();
-    ProjectName projectName = ProjectName.of(PROJECT_ID);
-    SecretName secretName = SecretName.of(PROJECT_ID, SECRET_ID);
-
-    try {
-      client.getSecret(secretName);
-    } catch (Exception e) {
-      com.google.cloud.secretmanager.v1.Secret secret =
-          com.google.cloud.secretmanager.v1.Secret.newBuilder()
-              .setReplication(
-                  com.google.cloud.secretmanager.v1.Replication.newBuilder()
-                      .setAutomatic(
-                          
com.google.cloud.secretmanager.v1.Replication.Automatic.newBuilder()
-                              .build())
-                      .build())
-              .build();
-      client.createSecret(projectName, SECRET_ID, secret);
-      byte[] secretBytes = new byte[32];
-      new SecureRandom().nextBytes(secretBytes);
-      client.addSecretVersion(
-          secretName,
-          SecretPayload.newBuilder()
-              
.setData(ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
-              .build());
-    }
-    gcpSecret = new GcpSecret(secretName.toString() + "/versions/latest");
-
-    try {
-      com.google.cloud.kms.v1.KeyManagementServiceClient kmsClient =
-          com.google.cloud.kms.v1.KeyManagementServiceClient.create();
-      String locationId = "global";
-      com.google.cloud.kms.v1.KeyRingName keyRingName =
-          com.google.cloud.kms.v1.KeyRingName.of(PROJECT_ID, locationId, 
KEY_RING_ID);
-      com.google.cloud.kms.v1.LocationName locationName =
-          com.google.cloud.kms.v1.LocationName.of(PROJECT_ID, locationId);
-      try {
-        kmsClient.getKeyRing(keyRingName);
-      } catch (Exception e) {
-        kmsClient.createKeyRing(
-            locationName, KEY_RING_ID, 
com.google.cloud.kms.v1.KeyRing.newBuilder().build());
-      }
-
-      com.google.cloud.kms.v1.CryptoKeyName keyName =
-          com.google.cloud.kms.v1.CryptoKeyName.of(PROJECT_ID, locationId, 
KEY_RING_ID, KEY_ID);
-      try {
-        kmsClient.getCryptoKey(keyName);
-      } catch (Exception e) {
-        com.google.cloud.kms.v1.CryptoKey key =
-            com.google.cloud.kms.v1.CryptoKey.newBuilder()
-                
.setPurpose(com.google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT)
-                .build();
-        kmsClient.createCryptoKey(keyRingName, KEY_ID, key);
-      }
-      gcpHsmGeneratedSecret =
-          new GcpHsmGeneratedSecret(
-              PROJECT_ID,
-              locationId,
-              KEY_RING_ID,
-              KEY_ID,
-              String.format("gbek-test-job-%d", new 
SecureRandom().nextInt(10000)));
-      // Validate we have crypto permissions or skip these tests.
-      gcpHsmGeneratedSecret.getSecretBytes();
-    } catch (Exception e) {
-      gcpHsmGeneratedSecret = null;
-    }
-  }
-
-  @AfterClass
-  public static void tearDown() throws IOException {
-    SecretManagerServiceClient client = SecretManagerServiceClient.create();
-    SecretName secretName = SecretName.of(PROJECT_ID, SECRET_ID);
-    client.deleteSecret(secretName);
-  }
-
-  @Test
-  @Category(NeedsRunner.class)
-  public void testGroupByKeyGcpSecret() {
-    List<KV<@Nullable String, Integer>> ungroupedPairs =
-        Arrays.asList(
-            KV.of(null, 3),
-            KV.of("k1", 3),
-            KV.of("k5", Integer.MAX_VALUE),
-            KV.of("k5", Integer.MIN_VALUE),
-            KV.of("k2", 66),
-            KV.of("k1", 4),
-            KV.of(null, 5),
-            KV.of("k2", -33),
-            KV.of("k3", 0));
-
-    PCollection<KV<String, Integer>> input =
-        p.apply(
-            Create.of(ungroupedPairs)
-                .withCoder(KvCoder.of(NullableCoder.of(StringUtf8Coder.of()), 
VarIntCoder.of())));
-
-    PCollection<KV<String, Iterable<Integer>>> output =
-        input.apply(GroupByEncryptedKey.<String, Integer>create(gcpSecret));
-
-    PAssert.that(output.apply("Sort", MapElements.via(new SortValues())))
-        .containsInAnyOrder(
-            KV.of("k1", Arrays.asList(3, 4)),
-            KV.of(null, Arrays.asList(3, 5)),
-            KV.of("k5", Arrays.asList(Integer.MIN_VALUE, Integer.MAX_VALUE)),
-            KV.of("k2", Arrays.asList(-33, 66)),
-            KV.of("k3", Arrays.asList(0)));
-
-    p.run();
-  }
-
-  @Test
-  @Category(NeedsRunner.class)
-  public void testGroupByKeyGcpSecretThrows() {
-    Secret gcpSecret = new GcpSecret("bad_path/versions/latest");
-    p.apply(Create.of(KV.of("k1", 1)))
-        .apply(GroupByEncryptedKey.<String, Integer>create(gcpSecret));
-    assertThrows(RuntimeException.class, () -> p.run());
-  }
-
   @Test
   @Category(NeedsRunner.class)
-  public void testGroupByKeyGcpHsmGeneratedSecret() {
-    if (gcpHsmGeneratedSecret == null) {
-      return;
-    }
+  public void testGroupByKeyRawSecret() {
     List<KV<@Nullable String, Integer>> ungroupedPairs =
         Arrays.asList(
             KV.of(null, 3),
@@ -249,8 +110,12 @@ public class GroupByEncryptedKeyTest implements 
Serializable {
             Create.of(ungroupedPairs)
                 .withCoder(KvCoder.of(NullableCoder.of(StringUtf8Coder.of()), 
VarIntCoder.of())));
 
+    // GroupByEncryptedKey expects Secret#getSecretBytes() to return 
Base64-URL encoded
+    // bytes of a valid AES key (e.g. 32 bytes for AES-256).
+    byte[] secretBytes = 
"test-encryption-key-secret-12345".getBytes(StandardCharsets.UTF_8);
+    Secret rawSecret = new 
RawSecret(Base64.getUrlEncoder().encode(secretBytes));
     PCollection<KV<String, Iterable<Integer>>> output =
-        input.apply(GroupByEncryptedKey.<String, 
Integer>create(gcpHsmGeneratedSecret));
+        input.apply(GroupByEncryptedKey.<String, Integer>create(rawSecret));
 
     PAssert.that(output.apply("Sort", MapElements.via(new SortValues())))
         .containsInAnyOrder(
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyTest.java
 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyTest.java
index 3ff98d47939..5464838ad4d 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyTest.java
+++ 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyTest.java
@@ -26,18 +26,12 @@ import static org.hamcrest.Matchers.empty;
 import static 
org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
 import static org.junit.Assert.assertThrows;
 
-import com.google.cloud.secretmanager.v1.ProjectName;
-import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
-import com.google.cloud.secretmanager.v1.SecretName;
-import com.google.cloud.secretmanager.v1.SecretPayload;
-import com.google.protobuf.ByteString;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
-import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -96,9 +90,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import org.hamcrest.Matcher;
 import org.joda.time.Duration;
 import org.joda.time.Instant;
-import org.junit.AfterClass;
 import org.junit.Assert;
-import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -624,110 +616,6 @@ public class GroupByKeyTest implements Serializable {
     }
   }
 
-  /** Tests validating GroupByKey behaviors with the gbek flag set. */
-  @RunWith(JUnit4.class)
-  public static class GbekTests extends SharedTestBase {
-    private static final String PROJECT_ID = "apache-beam-testing";
-    private static final String SECRET_ID = "gbek-test";
-    public static String gcpSecretVersionName;
-    private static String secretId;
-
-    @BeforeClass
-    public static void setup() throws IOException {
-      secretId = String.format("%s-%d", SECRET_ID, new 
SecureRandom().nextInt(10000));
-      SecretManagerServiceClient client;
-      try {
-        client = SecretManagerServiceClient.create();
-      } catch (IOException e) {
-        gcpSecretVersionName = null;
-        return;
-      }
-      ProjectName projectName = ProjectName.of(PROJECT_ID);
-      SecretName secretName = SecretName.of(PROJECT_ID, secretId);
-
-      try {
-        client.getSecret(secretName);
-      } catch (Exception e) {
-        com.google.cloud.secretmanager.v1.Secret secret =
-            com.google.cloud.secretmanager.v1.Secret.newBuilder()
-                .setReplication(
-                    com.google.cloud.secretmanager.v1.Replication.newBuilder()
-                        .setAutomatic(
-                            
com.google.cloud.secretmanager.v1.Replication.Automatic.newBuilder()
-                                .build())
-                        .build())
-                .build();
-        client.createSecret(projectName, secretId, secret);
-        byte[] secretBytes = new byte[32];
-        new SecureRandom().nextBytes(secretBytes);
-        client.addSecretVersion(
-            secretName,
-            SecretPayload.newBuilder()
-                
.setData(ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
-                .build());
-      }
-      gcpSecretVersionName = secretName.toString() + "/versions/latest";
-    }
-
-    @AfterClass
-    public static void tearDown() throws IOException {
-      if (gcpSecretVersionName != null) {
-        SecretManagerServiceClient client = 
SecretManagerServiceClient.create();
-        SecretName secretName = SecretName.of(PROJECT_ID, secretId);
-        client.deleteSecret(secretName);
-      }
-    }
-
-    @Test
-    @Category(NeedsRunner.class)
-    public void testGroupByKeyWithValidGcpSecretOption() {
-      if (gcpSecretVersionName == null) {
-        // Skip test if we couldn't set up secret manager
-        return;
-      }
-      List<KV<String, Integer>> ungroupedPairs =
-          Arrays.asList(
-              KV.of("k1", 3),
-              KV.of("k5", Integer.MAX_VALUE),
-              KV.of("k5", Integer.MIN_VALUE),
-              KV.of("k2", 66),
-              KV.of("k1", 4),
-              KV.of("k2", -33),
-              KV.of("k3", 0));
-
-      PCollection<KV<String, Integer>> input =
-          p.apply(
-              Create.of(ungroupedPairs)
-                  .withCoder(KvCoder.of(StringUtf8Coder.of(), 
BigEndianIntegerCoder.of())));
-
-      p.getOptions().setGbek(String.format("type:gcpsecret;version_name:%s", 
gcpSecretVersionName));
-      PCollection<KV<String, Iterable<Integer>>> output = 
input.apply(GroupByKey.create());
-
-      SerializableFunction<Iterable<KV<String, Iterable<Integer>>>, Void> 
checker =
-          containsKvs(
-              kv("k1", 3, 4),
-              kv("k5", Integer.MIN_VALUE, Integer.MAX_VALUE),
-              kv("k2", 66, -33),
-              kv("k3", 0));
-      PAssert.that(output).satisfies(checker);
-      PAssert.that(output).inWindow(GlobalWindow.INSTANCE).satisfies(checker);
-
-      p.run();
-    }
-
-    @Test
-    @Category(NeedsRunner.class)
-    public void testGroupByKeyWithInvalidGcpSecretOption() {
-      if (gcpSecretVersionName == null) {
-        // Skip test if we couldn't set up secret manager
-        return;
-      }
-      
p.getOptions().setGbek("type:gcpsecret;version_name:bad_path/versions/latest");
-      p.apply(Create.of(KV.of("k1", 1))).apply(GroupByKey.create());
-      assertThrows(RuntimeException.class, () -> p.run());
-    }
-  }
-
   /** Tests validating GroupByKey behaviors with windowing. */
   @RunWith(JUnit4.class)
   public static class WindowTests extends SharedTestBase {
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java
index 446688035a5..6810ea307b4 100644
--- a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java
+++ b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java
@@ -30,7 +30,6 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import org.apache.beam.sdk.util.common.ReflectHelpers;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -39,39 +38,6 @@ import org.junit.runners.JUnit4;
 @RunWith(JUnit4.class)
 public class SecretTest {
 
-  @Test
-  public void testParseSecretOptionWithValidGcpSecret() {
-    String secretOption = 
"type:gcpsecret;version_name:my_secret/versions/latest";
-    Secret secret = Secret.parseSecretOption(secretOption);
-    assertTrue(secret instanceof GcpSecret);
-    assertEquals("my_secret/versions/latest", ((GcpSecret) 
secret).getVersionName());
-    assertEquals(new GcpSecret("my_secret/versions/latest"), secret);
-
-    Secret secretFoo = 
Secret.parseSecretOption("type:GcpSecret;version_name:foo");
-    assertEquals(new GcpSecret("foo"), secretFoo);
-
-    Secret secretMixedCase =
-        
Secret.parseSecretOption("type:gcpsecreT;version_name:my_secret/versions/latest");
-    assertEquals(new GcpSecret("my_secret/versions/latest"), secretMixedCase);
-  }
-
-  @Test
-  public void testParseSecretOptionWithValidGcpHsmGeneratedSecret() {
-    String secretOption =
-        
"type:gcphsmgeneratedsecret;project_id:my-project;location_id:global;key_ring_id:my-key-ring;key_id:my-key;job_name:my-job";
-    Secret secret = Secret.parseSecretOption(secretOption);
-    assertTrue(secret instanceof GcpHsmGeneratedSecret);
-    GcpHsmGeneratedSecret hsmSecret = (GcpHsmGeneratedSecret) secret;
-    assertEquals("my-project", hsmSecret.getProjectId());
-    assertEquals("global", hsmSecret.getLocationId());
-    assertEquals("my-key-ring", hsmSecret.getKeyRingId());
-    assertEquals("my-key", hsmSecret.getKeyId());
-    assertEquals("HsmGeneratedSecret_my-job", hsmSecret.getSecretId());
-    assertEquals(
-        new GcpHsmGeneratedSecret("my-project", "global", "my-key-ring", 
"my-key", "my-job"),
-        secret);
-  }
-
   @Test
   public void testParseSecretOptionWithMissingType() {
     String secretOption = "version_name:my_secret/versions/latest";
@@ -86,24 +52,6 @@ public class SecretTest {
     Exception exception =
         assertThrows(IllegalArgumentException.class, () -> 
Secret.parseSecretOption(secretOption));
     assertTrue(exception.getMessage().contains("Invalid secret type 
unsupported"));
-    assertTrue(exception.getMessage().contains("GcpSecret"));
-    assertTrue(exception.getMessage().contains("GoogleCloudSecretManager"));
-  }
-
-  @Test
-  public void testParseSecretOptionWithInvalidGcpSecretParameter() {
-    String secretOption = "type:gcpsecret;invalid_param:some_value";
-    Exception exception =
-        assertThrows(IllegalArgumentException.class, () -> 
Secret.parseSecretOption(secretOption));
-    assertTrue(exception.getMessage().contains("Invalid secret parameter 
invalid_param"));
-  }
-
-  @Test
-  public void testParseSecretOptionWithMissingSecretName() {
-    String secretOption = "type:gcpsecreT";
-    Exception exception =
-        assertThrows(IllegalArgumentException.class, () -> 
Secret.parseSecretOption(secretOption));
-    assertTrue(exception.getMessage().contains("Secret name must be specified 
in secret spec."));
   }
 
   @Test
@@ -128,21 +76,6 @@ public class SecretTest {
 
   @Test
   public void testSecretFactory() {
-    String spec = "{\"name\": \"test-secret\", \"project\": \"proj\"}";
-
-    Secret secretGcp = Secret.fromJson(spec, "GoogleCloudSecretManager");
-    assertTrue(secretGcp instanceof GcpSecret);
-    assertEquals(
-        "projects/proj/secrets/test-secret/versions/latest",
-        ((GcpSecret) secretGcp).getVersionName());
-
-    String singleQuotedSpec = "{'name': 'test-secret', 'project': 'proj'}";
-    Secret secretSingleQuoted = Secret.fromJson(singleQuotedSpec, 
"GoogleCloudSecretManager");
-    assertTrue(secretSingleQuoted instanceof GcpSecret);
-    assertEquals(
-        "projects/proj/secrets/test-secret/versions/latest",
-        ((GcpSecret) secretSingleQuoted).getVersionName());
-
     Secret secretRaw = Secret.fromJson("STATIC_SECRET_", null);
     assertTrue(secretRaw instanceof RawSecret);
     assertEquals("STATIC_SECRET_", secretRaw.getString());
@@ -152,23 +85,6 @@ public class SecretTest {
             IllegalArgumentException.class, () -> Secret.fromJson("spec", 
"unsupported_provider"));
     assertTrue(
         exception.getMessage().contains("Unsupported secret manager: 
'unsupported_provider'"));
-    assertTrue(exception.getMessage().contains("GoogleCloudSecretManager"));
-    assertTrue(exception.getMessage().contains("GcpSecret"));
-
-    // Case-insensitive secret manager lookup in fromJson
-    Secret secretGcpLower = Secret.fromJson(spec, "googlecloudsecretmanager");
-    assertTrue(secretGcpLower instanceof GcpSecret);
-    Secret secretShortLower = Secret.fromJson(spec, "gcpsecret");
-    assertTrue(secretShortLower instanceof GcpSecret);
-  }
-
-  @Test
-  public void testSecretFactoryHsm() {
-    String hsmSpec =
-        "{\"project_id\": \"p\", \"location_id\": \"l\", \"key_ring_id\": 
\"r\", \"key_id\": \"k\", \"job_name\": \"j\"}";
-    Secret secretHsm = Secret.fromJson(hsmSpec, 
"GoogleCloudHsmGeneratedSecretManager");
-    assertTrue(secretHsm instanceof GcpHsmGeneratedSecret);
-    assertEquals("p", ((GcpHsmGeneratedSecret) secretHsm).getProjectId());
   }
 
   @Test
@@ -188,60 +104,6 @@ public class SecretTest {
     assertNotEquals(raw1, raw3);
     assertFalse(raw1.equals("secret_value"));
     assertFalse(raw1.equals(null));
-
-    Map<String, String> spec1 = new HashMap<>();
-    spec1.put("name", "sec");
-    spec1.put("project", "proj");
-    Map<String, String> spec2 = new HashMap<>();
-    spec2.put("name", "sec");
-    spec2.put("project", "proj");
-    Map<String, String> spec3 = new HashMap<>();
-    spec3.put("name", "other");
-    spec3.put("project", "proj");
-
-    GcpSecret gcp1 = GcpSecret.fromMap(spec1);
-    GcpSecret gcp2 = GcpSecret.fromMap(spec2);
-    GcpSecret gcp3 = GcpSecret.fromMap(spec3);
-    assertEquals(gcp1, gcp2);
-    assertEquals(gcp1.hashCode(), gcp2.hashCode());
-    assertNotEquals(gcp1, gcp3);
-    assertFalse(gcp1.equals(raw1));
-    assertFalse(gcp1.equals(null));
-
-    GcpHsmGeneratedSecret hsm1 = new GcpHsmGeneratedSecret("p", "l", "r", "k", 
"j");
-    GcpHsmGeneratedSecret hsm2 = new GcpHsmGeneratedSecret("p", "l", "r", "k", 
"j");
-    GcpHsmGeneratedSecret hsm3 = new GcpHsmGeneratedSecret("p", "l", "r", "k", 
"other");
-    assertEquals(hsm1, hsm2);
-    assertEquals(hsm1.hashCode(), hsm2.hashCode());
-    assertNotEquals(hsm1, hsm3);
-    assertFalse(hsm1.equals(gcp1));
-    assertFalse(hsm1.equals(null));
-  }
-
-  @Test
-  public void testGcpSecretFromMapMissingSecretNameThrows() {
-    Map<String, String> spec = Collections.singletonMap("project", 
"my-project");
-    Exception exception =
-        assertThrows(IllegalArgumentException.class, () -> 
GcpSecret.fromMap(spec));
-    assertTrue(exception.getMessage().contains("Secret name must be 
specified"));
-  }
-
-  @Test
-  public void testGcpHsmGeneratedSecretFromMapMissingParamsThrows() {
-    Map<String, String> spec = new HashMap<>();
-    spec.put("project_id", "test-proj");
-    spec.put("location_id", "global");
-    Exception exception =
-        assertThrows(NullPointerException.class, () -> 
GcpHsmGeneratedSecret.fromMap(spec));
-    assertTrue(
-        exception
-            .getMessage()
-            .contains("key_ring_id must contain a valid value for keyRingId 
parameter"));
-  }
-
-  @Test
-  public void testResolveGcpProjectIdExplicit() {
-    assertEquals("my-proj", GcpSecret.resolveGcpProjectId("my-proj", 
"context"));
   }
 
   @Test
@@ -249,14 +111,6 @@ public class SecretTest {
     RawSecret raw = new RawSecret("test_secret");
     RawSecret deserializedRaw = SerializableUtils.clone(raw);
     assertEquals(raw, deserializedRaw);
-
-    GcpSecret gcp = new GcpSecret("projects/p/secrets/s/versions/1");
-    GcpSecret deserializedGcp = SerializableUtils.clone(gcp);
-    assertEquals(gcp, deserializedGcp);
-
-    GcpHsmGeneratedSecret hsm = new GcpHsmGeneratedSecret("p", "l", "r", "k", 
"j");
-    GcpHsmGeneratedSecret deserializedHsm = SerializableUtils.clone(hsm);
-    assertEquals(hsm, deserializedHsm);
   }
 
   @Test
@@ -319,19 +173,4 @@ public class SecretTest {
     assertEquals(factory1, factories.get("duplicate_key"));
     assertEquals(Collections.singleton("duplicate_key"), supportedTypes);
   }
-
-  @Test
-  public void testLoadServicesOrderedDiscoversSecretRegistrars() {
-    Iterable<SecretRegistrar> registrars =
-        ReflectHelpers.loadServicesOrdered(SecretRegistrar.class);
-    org.junit.Assert.assertNotNull(registrars);
-    boolean foundGcp = false;
-    for (SecretRegistrar registrar : registrars) {
-      if (registrar instanceof GcpSecretRegistrar) {
-        foundGcp = true;
-        break;
-      }
-    }
-    assertTrue("Expected GcpSecretRegistrar to be discovered", foundGcp);
-  }
 }
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecretRegistrar.java 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/TestSecretRegistrar.java
similarity index 80%
copy from 
sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecretRegistrar.java
copy to 
sdks/java/core/src/test/java/org/apache/beam/sdk/util/TestSecretRegistrar.java
index 61b31332e6d..3a3b6ae83e0 100644
--- 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecretRegistrar.java
+++ 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/TestSecretRegistrar.java
@@ -18,17 +18,17 @@
 package org.apache.beam.sdk.util;
 
 import com.google.auto.service.AutoService;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap;
 
-/** {@link AutoService} registrar for the {@link GcpSecret}. */
+/** Test {@link SecretRegistrar} for unit and cross-language tests. */
 @AutoService(SecretRegistrar.class)
-public class GcpSecretRegistrar implements SecretRegistrar {
+public class TestSecretRegistrar implements SecretRegistrar {
 
   @Override
   public Map<String, SecretFactory> getSecretFactories() {
     return ImmutableMap.of(
-        "GoogleCloudSecretManager", GcpSecret::fromMap,
-        "GcpSecret", GcpSecret::fromMap);
+        "TestSecret", spec -> new 
RawSecret(spec.get("secret").getBytes(StandardCharsets.UTF_8)));
   }
 }
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/ValidateRunnerXlangTest.java
 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/ValidateRunnerXlangTest.java
index 6db2105caf7..1b4fbc10df6 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/ValidateRunnerXlangTest.java
+++ 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/ValidateRunnerXlangTest.java
@@ -20,15 +20,11 @@ package org.apache.beam.sdk.util.construction;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 
-import com.google.cloud.secretmanager.v1.ProjectName;
-import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
-import com.google.cloud.secretmanager.v1.SecretName;
-import com.google.cloud.secretmanager.v1.SecretPayload;
-import com.google.protobuf.ByteString;
 import java.io.IOException;
 import java.io.Serializable;
-import java.security.SecureRandom;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.Base64;
 import org.apache.beam.model.pipeline.v1.ExternalTransforms;
 import org.apache.beam.sdk.Pipeline;
 import org.apache.beam.sdk.PipelineResult;
@@ -55,7 +51,6 @@ import org.apache.beam.sdk.values.Row;
 import org.apache.beam.sdk.values.TypeDescriptors;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.Iterables;
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
@@ -89,7 +84,7 @@ import org.junit.runners.JUnit4;
  * details.
  */
 public class ValidateRunnerXlangTest {
-  static class ValidateRunnerXlangTestBase extends BaseExternalTest implements 
Serializable {
+  public static class ValidateRunnerXlangTestBase extends BaseExternalTest 
implements Serializable {
     // URNs for core cross-language transforms.
     // See 
https://docs.google.com/document/d/1xQp0ElIV84b8OCVz8CD2hvbiWdR8w4BvWxPTZJZA6NA 
for
     // further
@@ -316,61 +311,13 @@ public class ValidateRunnerXlangTest {
   @RunWith(JUnit4.class)
   public static class GroupByKeyWithGbekTest extends 
ValidateRunnerXlangTestBase {
     @Rule public ExpectedException thrown = ExpectedException.none();
-    private static final String PROJECT_ID = "apache-beam-testing";
-    private static final String SECRET_ID = "gbek-test";
-    private static String gcpSecretVersionName;
-    private static String secretId;
 
     @BeforeClass
     public static void setUpClass() {
-      secretId = String.format("%s-%d", SECRET_ID, new 
SecureRandom().nextInt(10000));
-      try (SecretManagerServiceClient client = 
SecretManagerServiceClient.create()) {
-        ProjectName projectName = ProjectName.of(PROJECT_ID);
-        SecretName secretName = SecretName.of(PROJECT_ID, secretId);
-
-        try {
-          client.getSecret(secretName);
-        } catch (Exception e) {
-          com.google.cloud.secretmanager.v1.Secret secret =
-              com.google.cloud.secretmanager.v1.Secret.newBuilder()
-                  .setReplication(
-                      
com.google.cloud.secretmanager.v1.Replication.newBuilder()
-                          .setAutomatic(
-                              
com.google.cloud.secretmanager.v1.Replication.Automatic.newBuilder()
-                                  .build())
-                          .build())
-                  .build();
-          client.createSecret(projectName, secretId, secret);
-          byte[] secretBytes = new byte[32];
-          new SecureRandom().nextBytes(secretBytes);
-          client.addSecretVersion(
-              secretName,
-              SecretPayload.newBuilder()
-                  .setData(
-                      
ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
-                  .build());
-        }
-        gcpSecretVersionName = secretName.toString() + "/versions/latest";
-      } catch (IOException e) {
-        gcpSecretVersionName = null;
-        return;
-      }
       expansionAddr =
           String.format("localhost:%s", 
Integer.valueOf(System.getProperty("expansionPort")));
     }
 
-    @AfterClass
-    public static void tearDownClass() {
-      if (gcpSecretVersionName != null) {
-        try (SecretManagerServiceClient client = 
SecretManagerServiceClient.create()) {
-          SecretName secretName = SecretName.of(PROJECT_ID, secretId);
-          client.deleteSecret(secretName);
-        } catch (IOException e) {
-          // Do nothing.
-        }
-      }
-    }
-
     @After
     @Override
     public void tearDown() {
@@ -385,12 +332,10 @@ public class ValidateRunnerXlangTest {
       UsesPythonExpansionService.class
     })
     public void test() {
-      if (gcpSecretVersionName == null) {
-        // Skip test if we couldn't set up secret manager
-        return;
-      }
+      byte[] secretBytes = 
"test-encryption-key-secret-12345".getBytes(StandardCharsets.UTF_8);
+      String base64Secret = Base64.getUrlEncoder().encodeToString(secretBytes);
       PipelineOptions options = TestPipeline.testingPipelineOptions();
-      options.setGbek(String.format("type:gcpsecret;version_name:%s", 
gcpSecretVersionName));
+      options.setGbek(String.format("type:testsecret;secret:%s", 
base64Secret));
       Pipeline pipeline = Pipeline.create(options);
       groupByKeyTest(pipeline);
       PipelineResult pipelineResult = pipeline.run();
diff --git a/sdks/java/extensions/google-cloud-platform-core/build.gradle 
b/sdks/java/extensions/google-cloud-platform-core/build.gradle
index 78cfe4739ec..3c6612070ad 100644
--- a/sdks/java/extensions/google-cloud-platform-core/build.gradle
+++ b/sdks/java/extensions/google-cloud-platform-core/build.gradle
@@ -59,6 +59,12 @@ dependencies {
   implementation library.java.jackson_core
   implementation library.java.jackson_databind
   permitUnusedDeclared library.java.jackson_databind // BEAM-11761
+  implementation library.java.google_cloud_kms
+  implementation library.java.proto_google_cloud_kms_v1
+  implementation library.java.google_cloud_tink
+  implementation library.java.google_cloud_secret_manager
+  implementation library.java.proto_google_cloud_secret_manager_v1
+  implementation library.java.protobuf_java
   testImplementation project(path: ":sdks:java:core", configuration: 
"shadowTest")
   testImplementation library.java.mockito_core
   testRuntimeOnly library.java.slf4j_jdk14
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpHsmGeneratedSecret.java
 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpHsmGeneratedSecret.java
similarity index 96%
rename from 
sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpHsmGeneratedSecret.java
rename to 
sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpHsmGeneratedSecret.java
index 9a62bc49d3c..c1227cbff56 100644
--- 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpHsmGeneratedSecret.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpHsmGeneratedSecret.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.util;
+package org.apache.beam.sdk.extensions.gcp.util;
 
 import com.google.api.gax.rpc.AlreadyExistsException;
 import com.google.api.gax.rpc.NotFoundException;
@@ -43,15 +43,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import org.apache.beam.sdk.util.Secret;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions;
 import org.checkerframework.checker.nullness.qual.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * A {@link org.apache.beam.sdk.util.Secret} manager implementation that 
generates a secret using
- * entropy from a GCP HSM key and stores it in Google Cloud Secret Manager. If 
the secret already
- * exists, it will be retrieved.
+ * A {@link Secret} manager implementation that generates a secret using 
entropy from a GCP HSM key
+ * and stores it in Google Cloud Secret Manager. If the secret already exists, 
it will be retrieved.
  */
 public class GcpHsmGeneratedSecret extends Secret {
   private static final Logger LOG = 
LoggerFactory.getLogger(GcpHsmGeneratedSecret.class);
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpHsmGeneratedSecretRegistrar.java
 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpHsmGeneratedSecretRegistrar.java
similarity index 93%
rename from 
sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpHsmGeneratedSecretRegistrar.java
rename to 
sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpHsmGeneratedSecretRegistrar.java
index 232fe7dfa83..ecdaf521ff0 100644
--- 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpHsmGeneratedSecretRegistrar.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpHsmGeneratedSecretRegistrar.java
@@ -15,10 +15,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.util;
+package org.apache.beam.sdk.extensions.gcp.util;
 
 import com.google.auto.service.AutoService;
 import java.util.Map;
+import org.apache.beam.sdk.util.SecretRegistrar;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap;
 
 /** {@link AutoService} registrar for the {@link GcpHsmGeneratedSecret}. */
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecret.java 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecret.java
similarity index 98%
rename from sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecret.java
rename to 
sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecret.java
index 9aaa61bc3e0..08329830599 100644
--- a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecret.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecret.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.util;
+package org.apache.beam.sdk.extensions.gcp.util;
 
 import com.google.cloud.secretmanager.v1.AccessSecretVersionResponse;
 import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
@@ -29,6 +29,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import org.apache.beam.sdk.util.Secret;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions;
 import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Strings;
 import org.checkerframework.checker.nullness.qual.Nullable;
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecretRegistrar.java 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretRegistrar.java
similarity index 93%
rename from 
sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecretRegistrar.java
rename to 
sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretRegistrar.java
index 61b31332e6d..600ffa53391 100644
--- 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/GcpSecretRegistrar.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretRegistrar.java
@@ -15,10 +15,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.util;
+package org.apache.beam.sdk.extensions.gcp.util;
 
 import com.google.auto.service.AutoService;
 import java.util.Map;
+import org.apache.beam.sdk.util.SecretRegistrar;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap;
 
 /** {@link AutoService} registrar for the {@link GcpSecret}. */
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/transforms/GcpGroupByEncryptedKeyTest.java
similarity index 80%
copy from 
sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
copy to 
sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/transforms/GcpGroupByEncryptedKeyTest.java
index a929d62d29d..9232677f56c 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByEncryptedKeyTest.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/transforms/GcpGroupByEncryptedKeyTest.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.transforms;
+package org.apache.beam.sdk.extensions.gcp.transforms;
 
 import static org.junit.Assert.assertThrows;
 
@@ -26,21 +26,26 @@ import com.google.cloud.secretmanager.v1.SecretPayload;
 import com.google.protobuf.ByteString;
 import java.io.IOException;
 import java.io.Serializable;
-import java.nio.charset.Charset;
 import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
+import org.apache.beam.sdk.coders.BigEndianIntegerCoder;
 import org.apache.beam.sdk.coders.KvCoder;
 import org.apache.beam.sdk.coders.NullableCoder;
 import org.apache.beam.sdk.coders.StringUtf8Coder;
 import org.apache.beam.sdk.coders.VarIntCoder;
+import org.apache.beam.sdk.extensions.gcp.util.GcpHsmGeneratedSecret;
+import org.apache.beam.sdk.extensions.gcp.util.GcpSecret;
 import org.apache.beam.sdk.testing.NeedsRunner;
 import org.apache.beam.sdk.testing.PAssert;
 import org.apache.beam.sdk.testing.TestPipeline;
-import org.apache.beam.sdk.util.GcpHsmGeneratedSecret;
-import org.apache.beam.sdk.util.GcpSecret;
+import org.apache.beam.sdk.transforms.Create;
+import org.apache.beam.sdk.transforms.GroupByEncryptedKey;
+import org.apache.beam.sdk.transforms.GroupByKey;
+import org.apache.beam.sdk.transforms.MapElements;
+import org.apache.beam.sdk.transforms.SimpleFunction;
 import org.apache.beam.sdk.util.Secret;
 import org.apache.beam.sdk.values.KV;
 import org.apache.beam.sdk.values.PCollection;
@@ -53,63 +58,29 @@ import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/** Tests for {@link GroupByEncryptedKey}. */
+/** Tests for {@link GroupByEncryptedKey} and GBEK pipeline options using GCP 
Secrets. */
 @RunWith(JUnit4.class)
-public class GroupByEncryptedKeyTest implements Serializable {
+public class GcpGroupByEncryptedKeyTest implements Serializable {
 
   @Rule public transient TestPipeline p = TestPipeline.create();
 
-  private static class FakeSecret extends Secret {
-    private final byte[] secret =
-        
"YUt3STJQbXFZRnQycDV0TktDeUJTNXFZV0hoSHNHWmM".getBytes(Charset.defaultCharset());
-
-    @Override
-    public byte[] getSecretBytes() {
-      return secret;
-    }
-  }
-
-  @Test
-  @Category(NeedsRunner.class)
-  public void testGroupByKeyFakeSecret() {
-    List<KV<String, Integer>> ungroupedPairs =
-        Arrays.asList(
-            KV.of("k1", 3),
-            KV.of("k5", Integer.MAX_VALUE),
-            KV.of("k5", Integer.MIN_VALUE),
-            KV.of("k2", 66),
-            KV.of("k1", 4),
-            KV.of("k2", -33),
-            KV.of("k3", 0));
-
-    PCollection<KV<String, Integer>> input =
-        p.apply(
-            Create.of(ungroupedPairs)
-                .withCoder(KvCoder.of(StringUtf8Coder.of(), 
VarIntCoder.of())));
-
-    PCollection<KV<String, Iterable<Integer>>> output =
-        input.apply(GroupByEncryptedKey.<String, Integer>create(new 
FakeSecret()));
-
-    PAssert.that(output.apply("Sort", MapElements.via(new SortValues())))
-        .containsInAnyOrder(
-            KV.of("k1", Arrays.asList(3, 4)),
-            KV.of("k5", Arrays.asList(Integer.MIN_VALUE, Integer.MAX_VALUE)),
-            KV.of("k2", Arrays.asList(-33, 66)),
-            KV.of("k3", Arrays.asList(0)));
-
-    p.run();
-  }
-
   private static final String PROJECT_ID = "apache-beam-testing";
   private static final String SECRET_ID = "gbek-test";
   private static Secret gcpSecret;
+  private static String gcpSecretVersionName;
   private static Secret gcpHsmGeneratedSecret;
   private static final String KEY_RING_ID = "gbek-test-key-ring";
   private static final String KEY_ID = "gbek-test-key";
 
   @BeforeClass
   public static void setup() throws IOException {
-    SecretManagerServiceClient client = SecretManagerServiceClient.create();
+    SecretManagerServiceClient client;
+    try {
+      client = SecretManagerServiceClient.create();
+    } catch (IOException e) {
+      gcpSecretVersionName = null;
+      return;
+    }
     ProjectName projectName = ProjectName.of(PROJECT_ID);
     SecretName secretName = SecretName.of(PROJECT_ID, SECRET_ID);
 
@@ -134,7 +105,8 @@ public class GroupByEncryptedKeyTest implements 
Serializable {
               
.setData(ByteString.copyFrom(java.util.Base64.getUrlEncoder().encode(secretBytes)))
               .build());
     }
-    gcpSecret = new GcpSecret(secretName.toString() + "/versions/latest");
+    gcpSecretVersionName = secretName.toString() + "/versions/latest";
+    gcpSecret = new GcpSecret(gcpSecretVersionName);
 
     try {
       com.google.cloud.kms.v1.KeyManagementServiceClient kmsClient =
@@ -178,14 +150,19 @@ public class GroupByEncryptedKeyTest implements 
Serializable {
 
   @AfterClass
   public static void tearDown() throws IOException {
-    SecretManagerServiceClient client = SecretManagerServiceClient.create();
-    SecretName secretName = SecretName.of(PROJECT_ID, SECRET_ID);
-    client.deleteSecret(secretName);
+    if (gcpSecretVersionName != null) {
+      SecretManagerServiceClient client = SecretManagerServiceClient.create();
+      SecretName secretName = SecretName.of(PROJECT_ID, SECRET_ID);
+      client.deleteSecret(secretName);
+    }
   }
 
   @Test
   @Category(NeedsRunner.class)
   public void testGroupByKeyGcpSecret() {
+    if (gcpSecret == null) {
+      return;
+    }
     List<KV<@Nullable String, Integer>> ungroupedPairs =
         Arrays.asList(
             KV.of(null, 3),
@@ -220,9 +197,9 @@ public class GroupByEncryptedKeyTest implements 
Serializable {
   @Test
   @Category(NeedsRunner.class)
   public void testGroupByKeyGcpSecretThrows() {
-    Secret gcpSecret = new GcpSecret("bad_path/versions/latest");
+    Secret badGcpSecret = new GcpSecret("bad_path/versions/latest");
     p.apply(Create.of(KV.of("k1", 1)))
-        .apply(GroupByEncryptedKey.<String, Integer>create(gcpSecret));
+        .apply(GroupByEncryptedKey.<String, Integer>create(badGcpSecret));
     assertThrows(RuntimeException.class, () -> p.run());
   }
 
@@ -263,6 +240,51 @@ public class GroupByEncryptedKeyTest implements 
Serializable {
     p.run();
   }
 
+  @Test
+  @Category(NeedsRunner.class)
+  public void testGroupByKeyWithValidGcpSecretOption() {
+    if (gcpSecretVersionName == null) {
+      return;
+    }
+    List<KV<String, Integer>> ungroupedPairs =
+        Arrays.asList(
+            KV.of("k1", 3),
+            KV.of("k5", Integer.MAX_VALUE),
+            KV.of("k5", Integer.MIN_VALUE),
+            KV.of("k2", 66),
+            KV.of("k1", 4),
+            KV.of("k2", -33),
+            KV.of("k3", 0));
+
+    PCollection<KV<String, Integer>> input =
+        p.apply(
+            Create.of(ungroupedPairs)
+                .withCoder(KvCoder.of(StringUtf8Coder.of(), 
BigEndianIntegerCoder.of())));
+
+    p.getOptions().setGbek(String.format("type:gcpsecret;version_name:%s", 
gcpSecretVersionName));
+    PCollection<KV<String, Iterable<Integer>>> output = 
input.apply(GroupByKey.create());
+
+    PAssert.that(output.apply("Sort", MapElements.via(new SortValues())))
+        .containsInAnyOrder(
+            KV.of("k1", Arrays.asList(3, 4)),
+            KV.of("k5", Arrays.asList(Integer.MIN_VALUE, Integer.MAX_VALUE)),
+            KV.of("k2", Arrays.asList(66, -33)),
+            KV.of("k3", Arrays.asList(0)));
+
+    p.run();
+  }
+
+  @Test
+  @Category(NeedsRunner.class)
+  public void testGroupByKeyWithInvalidGcpSecretOption() {
+    if (gcpSecretVersionName == null) {
+      return;
+    }
+    
p.getOptions().setGbek("type:gcpsecret;version_name:bad_path/versions/latest");
+    p.apply(Create.of(KV.of("k1", 1))).apply(GroupByKey.create());
+    assertThrows(RuntimeException.class, () -> p.run());
+  }
+
   private static class SortValues
       extends SimpleFunction<KV<String, Iterable<Integer>>, KV<String, 
List<Integer>>> {
     @Override
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyIT.java 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/transforms/GcpGroupByKeyIT.java
similarity index 97%
rename from 
sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyIT.java
rename to 
sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/transforms/GcpGroupByKeyIT.java
index 431bdf448be..e8d3466cf09 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/GroupByKeyIT.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/transforms/GcpGroupByKeyIT.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.transforms;
+package org.apache.beam.sdk.extensions.gcp.transforms;
 
 import com.google.cloud.kms.v1.CryptoKey;
 import com.google.cloud.kms.v1.CryptoKeyName;
@@ -34,10 +34,15 @@ import org.apache.beam.sdk.Pipeline;
 import org.apache.beam.sdk.coders.KvCoder;
 import org.apache.beam.sdk.coders.StringUtf8Coder;
 import org.apache.beam.sdk.coders.VarIntCoder;
+import org.apache.beam.sdk.extensions.gcp.util.GcpHsmGeneratedSecret;
 import org.apache.beam.sdk.options.PipelineOptions;
 import org.apache.beam.sdk.testing.PAssert;
 import org.apache.beam.sdk.testing.TestPipeline;
-import org.apache.beam.sdk.util.GcpHsmGeneratedSecret;
+import org.apache.beam.sdk.transforms.Combine;
+import org.apache.beam.sdk.transforms.Create;
+import org.apache.beam.sdk.transforms.GroupByKey;
+import org.apache.beam.sdk.transforms.Redistribute;
+import org.apache.beam.sdk.transforms.Sum;
 import org.apache.beam.sdk.values.KV;
 import org.apache.beam.sdk.values.PCollection;
 import org.junit.AfterClass;
@@ -50,7 +55,7 @@ import org.junit.runners.JUnit4;
 
 /** Integration test for GroupByKey transforms and some other transforms which 
use GBK. */
 @RunWith(JUnit4.class)
-public class GroupByKeyIT {
+public class GcpGroupByKeyIT {
   @Rule public ExpectedException thrown = ExpectedException.none();
 
   private static final String PROJECT_ID = "apache-beam-testing";
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/GcpSecretRegistrarTest.java
 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretRegistrarTest.java
similarity index 96%
rename from 
sdks/java/core/src/test/java/org/apache/beam/sdk/util/GcpSecretRegistrarTest.java
rename to 
sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretRegistrarTest.java
index e95483dd9bf..f8d3708f8d3 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/GcpSecretRegistrarTest.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretRegistrarTest.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.util;
+package org.apache.beam.sdk.extensions.gcp.util;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasItems;
@@ -23,6 +23,7 @@ import static org.junit.Assert.fail;
 
 import java.util.Map;
 import java.util.ServiceLoader;
+import org.apache.beam.sdk.util.SecretRegistrar;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.Lists;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretTest.java
similarity index 62%
copy from sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java
copy to 
sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretTest.java
index 446688035a5..c493c642dc2 100644
--- a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/SecretTest.java
+++ 
b/sdks/java/extensions/google-cloud-platform-core/src/test/java/org/apache/beam/sdk/extensions/gcp/util/GcpSecretTest.java
@@ -15,29 +15,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.beam.sdk.util;
+package org.apache.beam.sdk.extensions.gcp.util;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
-import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import org.apache.beam.sdk.util.common.ReflectHelpers;
+import org.apache.beam.sdk.util.RawSecret;
+import org.apache.beam.sdk.util.Secret;
+import org.apache.beam.sdk.util.SerializableUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/** Tests for {@link org.apache.beam.sdk.util.Secret}. */
+/** Tests for {@link GcpSecret} and {@link GcpHsmGeneratedSecret}. */
 @RunWith(JUnit4.class)
-public class SecretTest {
+public class GcpSecretTest {
 
   @Test
   public void testParseSecretOptionWithValidGcpSecret() {
@@ -72,24 +70,6 @@ public class SecretTest {
         secret);
   }
 
-  @Test
-  public void testParseSecretOptionWithMissingType() {
-    String secretOption = "version_name:my_secret/versions/latest";
-    Exception exception =
-        assertThrows(IllegalArgumentException.class, () -> 
Secret.parseSecretOption(secretOption));
-    assertEquals("Secret string must contain a valid type parameter", 
exception.getMessage());
-  }
-
-  @Test
-  public void testParseSecretOptionWithUnsupportedType() {
-    String secretOption = 
"type:unsupported;version_name:my_secret/versions/latest";
-    Exception exception =
-        assertThrows(IllegalArgumentException.class, () -> 
Secret.parseSecretOption(secretOption));
-    assertTrue(exception.getMessage().contains("Invalid secret type 
unsupported"));
-    assertTrue(exception.getMessage().contains("GcpSecret"));
-    assertTrue(exception.getMessage().contains("GoogleCloudSecretManager"));
-  }
-
   @Test
   public void testParseSecretOptionWithInvalidGcpSecretParameter() {
     String secretOption = "type:gcpsecret;invalid_param:some_value";
@@ -107,27 +87,7 @@ public class SecretTest {
   }
 
   @Test
-  public void testRawSecretStr() {
-    Secret secret = new RawSecret("STATIC_SECRET_");
-    assertEquals("STATIC_SECRET_", secret.getString(true));
-    assertEquals("STATIC_SECRET_", secret.getString(false));
-    assertEquals("STATIC_SECRET_", secret.getString());
-    assertArrayEquals("STATIC_SECRET_".getBytes(StandardCharsets.UTF_8), 
secret.getBytes(true));
-    assertArrayEquals("STATIC_SECRET_".getBytes(StandardCharsets.UTF_8), 
secret.getBytes());
-  }
-
-  @Test
-  public void testRawSecretBytes() {
-    byte[] bytes = "STATIC_BYTES_".getBytes(StandardCharsets.UTF_8);
-    Secret secret = new RawSecret(bytes);
-    assertEquals("STATIC_BYTES_", secret.getString(true));
-    assertEquals("STATIC_BYTES_", secret.getString());
-    assertArrayEquals(bytes, secret.getBytes(true));
-    assertArrayEquals(bytes, secret.getBytes());
-  }
-
-  @Test
-  public void testSecretFactory() {
+  public void testSecretFactoryGcp() {
     String spec = "{\"name\": \"test-secret\", \"project\": \"proj\"}";
 
     Secret secretGcp = Secret.fromJson(spec, "GoogleCloudSecretManager");
@@ -143,9 +103,11 @@ public class SecretTest {
         "projects/proj/secrets/test-secret/versions/latest",
         ((GcpSecret) secretSingleQuoted).getVersionName());
 
-    Secret secretRaw = Secret.fromJson("STATIC_SECRET_", null);
-    assertTrue(secretRaw instanceof RawSecret);
-    assertEquals("STATIC_SECRET_", secretRaw.getString());
+    // Case-insensitive secret manager lookup in fromJson
+    Secret secretGcpLower = Secret.fromJson(spec, "googlecloudsecretmanager");
+    assertTrue(secretGcpLower instanceof GcpSecret);
+    Secret secretShortLower = Secret.fromJson(spec, "gcpsecret");
+    assertTrue(secretShortLower instanceof GcpSecret);
 
     Exception exception =
         assertThrows(
@@ -154,12 +116,32 @@ public class SecretTest {
         exception.getMessage().contains("Unsupported secret manager: 
'unsupported_provider'"));
     assertTrue(exception.getMessage().contains("GoogleCloudSecretManager"));
     assertTrue(exception.getMessage().contains("GcpSecret"));
+  }
 
-    // Case-insensitive secret manager lookup in fromJson
-    Secret secretGcpLower = Secret.fromJson(spec, "googlecloudsecretmanager");
-    assertTrue(secretGcpLower instanceof GcpSecret);
-    Secret secretShortLower = Secret.fromJson(spec, "gcpsecret");
-    assertTrue(secretShortLower instanceof GcpSecret);
+  @Test
+  public void testParseSecretOptionWithUnsupportedTypeListsGcpSecrets() {
+    String secretOption = 
"type:unsupported;version_name:my_secret/versions/latest";
+    Exception exception =
+        assertThrows(IllegalArgumentException.class, () -> 
Secret.parseSecretOption(secretOption));
+    assertTrue(exception.getMessage().contains("Invalid secret type 
unsupported"));
+    assertTrue(exception.getMessage().contains("GcpSecret"));
+    assertTrue(exception.getMessage().contains("GoogleCloudSecretManager"));
+  }
+
+  @Test
+  public void testLoadServicesOrderedDiscoversSecretRegistrars() {
+    Iterable<org.apache.beam.sdk.util.SecretRegistrar> registrars =
+        org.apache.beam.sdk.util.common.ReflectHelpers.loadServicesOrdered(
+            org.apache.beam.sdk.util.SecretRegistrar.class);
+    org.junit.Assert.assertNotNull(registrars);
+    boolean foundGcp = false;
+    for (org.apache.beam.sdk.util.SecretRegistrar registrar : registrars) {
+      if (registrar instanceof GcpSecretRegistrar) {
+        foundGcp = true;
+        break;
+      }
+    }
+    assertTrue("Expected GcpSecretRegistrar to be discovered", foundGcp);
   }
 
   @Test
@@ -171,23 +153,9 @@ public class SecretTest {
     assertEquals("p", ((GcpHsmGeneratedSecret) secretHsm).getProjectId());
   }
 
-  @Test
-  public void testJsonSecretWithoutSecretManagerWarning() {
-    String jsonSpec = "{\"name\": \"my-secret\", \"project\": \"my-proj\"}";
-    Secret secret = Secret.fromJson(jsonSpec, null);
-    assertTrue(secret instanceof RawSecret);
-  }
-
   @Test
   public void testEquality() {
     RawSecret raw1 = new RawSecret("secret_value");
-    RawSecret raw2 = new RawSecret("secret_value");
-    RawSecret raw3 = new RawSecret("other_value");
-    assertEquals(raw1, raw2);
-    assertEquals(raw1.hashCode(), raw2.hashCode());
-    assertNotEquals(raw1, raw3);
-    assertFalse(raw1.equals("secret_value"));
-    assertFalse(raw1.equals(null));
 
     Map<String, String> spec1 = new HashMap<>();
     spec1.put("name", "sec");
@@ -246,10 +214,6 @@ public class SecretTest {
 
   @Test
   public void testSerialization() {
-    RawSecret raw = new RawSecret("test_secret");
-    RawSecret deserializedRaw = SerializableUtils.clone(raw);
-    assertEquals(raw, deserializedRaw);
-
     GcpSecret gcp = new GcpSecret("projects/p/secrets/s/versions/1");
     GcpSecret deserializedGcp = SerializableUtils.clone(gcp);
     assertEquals(gcp, deserializedGcp);
@@ -258,80 +222,4 @@ public class SecretTest {
     GcpHsmGeneratedSecret deserializedHsm = SerializableUtils.clone(hsm);
     assertEquals(hsm, deserializedHsm);
   }
-
-  @Test
-  public void testLoadSecretFactoriesNullList() {
-    Map<String, SecretRegistrar.SecretFactory> factories = 
Secret.loadSecretFactories(null);
-    assertTrue(factories.isEmpty());
-  }
-
-  @Test
-  public void testLoadSecretFactoriesHandlesNullRegistrarAndNullFactories() {
-    SecretRegistrar nullFactoriesRegistrar = () -> null;
-    Map<String, SecretRegistrar.SecretFactory> factories =
-        Secret.loadSecretFactories(java.util.Arrays.asList(null, 
nullFactoriesRegistrar));
-    assertTrue(factories.isEmpty());
-  }
-
-  @Test
-  public void testLoadSecretFactoriesHandlesThrowingRegistrar() {
-    SecretRegistrar throwingRegistrar =
-        () -> {
-          throw new RuntimeException("Simulated failure in registrar");
-        };
-    SecretRegistrar validRegistrar =
-        () -> Collections.singletonMap("valid", spec -> new RawSecret("test"));
-
-    Map<String, SecretRegistrar.SecretFactory> factories =
-        Secret.loadSecretFactories(java.util.Arrays.asList(throwingRegistrar, 
validRegistrar));
-    assertEquals(1, factories.size());
-    assertTrue(factories.containsKey("valid"));
-  }
-
-  @Test
-  public void testLoadSecretFactoriesHandlesMalformedEntries() {
-    Map<String, SecretRegistrar.SecretFactory> malformedMap = new HashMap<>();
-    malformedMap.put(null, spec -> new RawSecret("val"));
-    malformedMap.put("", spec -> new RawSecret("val"));
-    malformedMap.put("   ", spec -> new RawSecret("val"));
-    malformedMap.put("null_factory", null);
-    malformedMap.put("good", spec -> new RawSecret("good_val"));
-
-    SecretRegistrar registrar = () -> malformedMap;
-    Map<String, SecretRegistrar.SecretFactory> factories =
-        Secret.loadSecretFactories(Collections.singletonList(registrar));
-    assertEquals(1, factories.size());
-    assertTrue(factories.containsKey("good"));
-  }
-
-  @Test
-  public void testLoadSecretFactoriesDuplicateKeysFirstWins() {
-    SecretRegistrar.SecretFactory factory1 = spec -> new RawSecret("first");
-    SecretRegistrar.SecretFactory factory2 = spec -> new RawSecret("second");
-
-    SecretRegistrar registrar1 = () -> 
Collections.singletonMap("duplicate_key", factory1);
-    SecretRegistrar registrar2 = () -> 
Collections.singletonMap("DUPLICATE_KEY", factory2);
-
-    Set<String> supportedTypes = new TreeSet<>();
-    Map<String, SecretRegistrar.SecretFactory> factories =
-        Secret.loadSecretFactories(java.util.Arrays.asList(registrar1, 
registrar2), supportedTypes);
-    assertEquals(1, factories.size());
-    assertEquals(factory1, factories.get("duplicate_key"));
-    assertEquals(Collections.singleton("duplicate_key"), supportedTypes);
-  }
-
-  @Test
-  public void testLoadServicesOrderedDiscoversSecretRegistrars() {
-    Iterable<SecretRegistrar> registrars =
-        ReflectHelpers.loadServicesOrdered(SecretRegistrar.class);
-    org.junit.Assert.assertNotNull(registrars);
-    boolean foundGcp = false;
-    for (SecretRegistrar registrar : registrars) {
-      if (registrar instanceof GcpSecretRegistrar) {
-        foundGcp = true;
-        break;
-      }
-    }
-    assertTrue("Expected GcpSecretRegistrar to be discovered", foundGcp);
-  }
 }
diff --git a/sdks/java/io/components/build.gradle 
b/sdks/java/io/components/build.gradle
index 97342009834..4d3fe55033d 100644
--- a/sdks/java/io/components/build.gradle
+++ b/sdks/java/io/components/build.gradle
@@ -37,7 +37,10 @@ dependencies {
     implementation library.java.vendored_guava_32_1_2_jre
     implementation library.java.vendored_grpc_1_69_0
 
+    testImplementation 
platform(library.java.google_cloud_platform_libraries_bom)
     testImplementation project(path: ":sdks:java:core", configuration: 
"shadowTest")
+    testImplementation library.java.grpc_inprocess
+    testRuntimeOnly library.java.grpc_netty_shaded
     testImplementation library.java.guava_testlib
     testImplementation library.java.junit
     testImplementation library.java.hamcrest
diff --git 
a/sdks/python/apache_beam/runners/portability/expansion_service_test.py 
b/sdks/python/apache_beam/runners/portability/expansion_service_test.py
index b0b0b2dd2bf..67ca6501880 100644
--- a/sdks/python/apache_beam/runners/portability/expansion_service_test.py
+++ b/sdks/python/apache_beam/runners/portability/expansion_service_test.py
@@ -39,8 +39,14 @@ from apache_beam.transforms import 
fully_qualified_named_transform
 from apache_beam.transforms import ptransform
 from apache_beam.transforms.environments import PyPIArtifactRegistry
 from apache_beam.transforms.external import ImplicitSchemaPayloadBuilder
+from apache_beam.utils import secret as beam_secret
 from apache_beam.utils import thread_pool_executor
 
+# Register TestSecret for cross-language GBEK validation tests.
+beam_secret._SECRET_TYPE_TO_SECRET_MANAGER["testsecret"] = "TestSecretManager"
+beam_secret._SECRET_CLASSES["testsecretmanager"] = (
+    lambda secret: beam_secret.RawSecret(secret.encode("utf-8")))
+
 # This script provides an expansion service and example ptransforms for running
 # external transform test cases. See external_test.py for details.
 

Reply via email to