From 3df08649c2b46c113579dcfbb715fe3441d06d70 Mon Sep 17 00:00:00 2001 From: Mattie Fu Date: Mon, 29 Jun 2026 10:49:42 -0400 Subject: [PATCH 1/4] fix: fallback on VPC --- .../dp/ClassicDirectAccessChecker.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java index ea11be7ce921..076229de52e9 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java @@ -22,11 +22,16 @@ import com.google.cloud.bigtable.gaxx.grpc.ChannelPrimer; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.protobuf.Any; +import com.google.rpc.ErrorInfo; +import com.google.rpc.PreconditionFailure; +import com.google.rpc.Status; import io.grpc.Channel; import io.grpc.ClientInterceptors; import io.grpc.ManagedChannel; import io.grpc.Status.Code; import io.grpc.StatusRuntimeException; +import io.grpc.protobuf.StatusProto; import java.util.Optional; import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Level; @@ -74,6 +79,46 @@ public boolean check(Channel channel) { } } + /** Checks if the exception is due to a VPC Service Controls policy violation. */ + private boolean isVpcScViolation(StatusRuntimeException e) { + try { + Status status = StatusProto.fromThrowable(e); + if (status != null) { + for (Any detail : status.getDetailsList()) { + // Check for ErrorInfo reason + if (detail.is(ErrorInfo.class)) { + ErrorInfo errorInfo = detail.unpack(ErrorInfo.class); + if ("VPC_SERVICE_CONTROLS".equals(errorInfo.getReason())) { + return true; + } + } + // Check for PreconditionFailure violation type + if (detail.is(PreconditionFailure.class)) { + PreconditionFailure failure = detail.unpack(PreconditionFailure.class); + for (PreconditionFailure.Violation violation : failure.getViolationsList()) { + if ("VPC_SERVICE_CONTROLS".equals(violation.getType())) { + return true; + } + } + } + } + } + } catch (Exception ex) { + // Fall back silently to string matching if protobuf unpacking fails + } + + // Check the error message if we can't parse ErrorDetails + String description = e.getStatus().getDescription(); + String message = e.getMessage(); + + return (description != null + && (description.contains("VPC Service Controls") + || description.contains("VPC_SERVICE_CONTROLS"))) + || (message != null + && (message.contains("VPC Service Controls") + || message.contains("VPC_SERVICE_CONTROLS"))); + } + /** Executes the underlying RPC and evaluates the eligibility. */ private boolean evaluateEligibility(Channel channel) { MetadataExtractorInterceptor interceptor = createInterceptor(); @@ -91,8 +136,15 @@ private boolean evaluateEligibility(Channel channel) { if (e.getStatus().getCode() != Code.PERMISSION_DENIED) { throw e; } - // Failed with permission error, resorting to ALTS check. - isEligible = sidebandData.isAlts(); + + if (isVpcScViolation(e)) { + LOG.log( + Level.WARNING, + "DirectPath is blocked by a VPC Service Controls perimeter policy violation."); + } else { + // Failed with standard permission error, resorting to ALTS check. + isEligible = sidebandData.isAlts(); + } } if (isEligible) { From 631ca3633e3c445f647b347a3affcfba11cc56af Mon Sep 17 00:00:00 2001 From: Mattie Fu Date: Mon, 29 Jun 2026 13:42:04 -0400 Subject: [PATCH 2/4] update error message --- .../dp/ClassicDirectAccessChecker.java | 48 ++----------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java index 076229de52e9..5d0ca84010d9 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java @@ -22,16 +22,11 @@ import com.google.cloud.bigtable.gaxx.grpc.ChannelPrimer; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; -import com.google.protobuf.Any; -import com.google.rpc.ErrorInfo; -import com.google.rpc.PreconditionFailure; -import com.google.rpc.Status; import io.grpc.Channel; import io.grpc.ClientInterceptors; import io.grpc.ManagedChannel; import io.grpc.Status.Code; import io.grpc.StatusRuntimeException; -import io.grpc.protobuf.StatusProto; import java.util.Optional; import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Level; @@ -80,43 +75,12 @@ public boolean check(Channel channel) { } /** Checks if the exception is due to a VPC Service Controls policy violation. */ - private boolean isVpcScViolation(StatusRuntimeException e) { - try { - Status status = StatusProto.fromThrowable(e); - if (status != null) { - for (Any detail : status.getDetailsList()) { - // Check for ErrorInfo reason - if (detail.is(ErrorInfo.class)) { - ErrorInfo errorInfo = detail.unpack(ErrorInfo.class); - if ("VPC_SERVICE_CONTROLS".equals(errorInfo.getReason())) { - return true; - } - } - // Check for PreconditionFailure violation type - if (detail.is(PreconditionFailure.class)) { - PreconditionFailure failure = detail.unpack(PreconditionFailure.class); - for (PreconditionFailure.Violation violation : failure.getViolationsList()) { - if ("VPC_SERVICE_CONTROLS".equals(violation.getType())) { - return true; - } - } - } - } - } - } catch (Exception ex) { - // Fall back silently to string matching if protobuf unpacking fails - } - - // Check the error message if we can't parse ErrorDetails + private boolean isAllowed(StatusRuntimeException e) { String description = e.getStatus().getDescription(); String message = e.getMessage(); - return (description != null - && (description.contains("VPC Service Controls") - || description.contains("VPC_SERVICE_CONTROLS"))) - || (message != null - && (message.contains("VPC Service Controls") - || message.contains("VPC_SERVICE_CONTROLS"))); + && description.contains("Request is prohibited by organization's policy")) + || (message != null && message.contains("Request is prohibited by organization's policy")); } /** Executes the underlying RPC and evaluates the eligibility. */ @@ -137,10 +101,8 @@ private boolean evaluateEligibility(Channel channel) { throw e; } - if (isVpcScViolation(e)) { - LOG.log( - Level.WARNING, - "DirectPath is blocked by a VPC Service Controls perimeter policy violation."); + if (isAllowed(e)) { + LOG.log(Level.WARNING, "DirectPath is blocked by a perimeter policy violation."); } else { // Failed with standard permission error, resorting to ALTS check. isEligible = sidebandData.isAlts(); From fc5dd887ceab77d7886677b77a8a715aa73463cc Mon Sep 17 00:00:00 2001 From: Mattie Fu Date: Mon, 29 Jun 2026 14:55:18 -0400 Subject: [PATCH 3/4] nit --- .../v2/internal/dp/ClassicDirectAccessChecker.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java index 5d0ca84010d9..47051fe6745e 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java @@ -75,12 +75,12 @@ public boolean check(Channel channel) { } /** Checks if the exception is due to a VPC Service Controls policy violation. */ - private boolean isAllowed(StatusRuntimeException e) { + private boolean isAllowedFromVPCServiceControls(StatusRuntimeException e) { String description = e.getStatus().getDescription(); String message = e.getMessage(); - return (description != null - && description.contains("Request is prohibited by organization's policy")) - || (message != null && message.contains("Request is prohibited by organization's policy")); + String expected = "request is prohibited by organization's policy"; + return (description != null && description.toLowerCase().contains(expected)) + || (message != null && message.toLowerCase().contains(expected)); } /** Executes the underlying RPC and evaluates the eligibility. */ @@ -101,7 +101,7 @@ private boolean evaluateEligibility(Channel channel) { throw e; } - if (isAllowed(e)) { + if (isAllowedFromVPCServiceControls(e)) { LOG.log(Level.WARNING, "DirectPath is blocked by a perimeter policy violation."); } else { // Failed with standard permission error, resorting to ALTS check. From 46589eda7eb0e37a6ca4e399737e06fa6c24e167 Mon Sep 17 00:00:00 2001 From: Mattie Fu Date: Mon, 29 Jun 2026 15:24:16 -0400 Subject: [PATCH 4/4] nit --- .../data/v2/internal/dp/ClassicDirectAccessChecker.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java index 47051fe6745e..ebbcccc564bd 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/dp/ClassicDirectAccessChecker.java @@ -27,6 +27,7 @@ import io.grpc.ManagedChannel; import io.grpc.Status.Code; import io.grpc.StatusRuntimeException; +import java.util.Locale; import java.util.Optional; import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Level; @@ -75,12 +76,12 @@ public boolean check(Channel channel) { } /** Checks if the exception is due to a VPC Service Controls policy violation. */ - private boolean isAllowedFromVPCServiceControls(StatusRuntimeException e) { + private boolean isVpcServiceControlsViolation(StatusRuntimeException e) { String description = e.getStatus().getDescription(); String message = e.getMessage(); String expected = "request is prohibited by organization's policy"; - return (description != null && description.toLowerCase().contains(expected)) - || (message != null && message.toLowerCase().contains(expected)); + return (description != null && description.toLowerCase(Locale.ROOT).contains(expected)) + || (message != null && message.toLowerCase(Locale.ROOT).contains(expected)); } /** Executes the underlying RPC and evaluates the eligibility. */ @@ -101,7 +102,7 @@ private boolean evaluateEligibility(Channel channel) { throw e; } - if (isAllowedFromVPCServiceControls(e)) { + if (isVpcServiceControlsViolation(e)) { LOG.log(Level.WARNING, "DirectPath is blocked by a perimeter policy violation."); } else { // Failed with standard permission error, resorting to ALTS check.