Skip to content

Configurable client builders and credential injection#3172

Merged
jeremydmiller merged 7 commits into
JasperFx:mainfrom
AurorNZ:worktree-lets-proceed-with-implementation-optimized-papert
Jun 22, 2026
Merged

Configurable client builders and credential injection#3172
jeremydmiller merged 7 commits into
JasperFx:mainfrom
AurorNZ:worktree-lets-proceed-with-implementation-optimized-papert

Conversation

@bittercoder

@bittercoder bittercoder commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Background

We utilise a combination of cloud providers (Azure and GCP) and in some cases have workloads hosted in Azure that need to utilise GCP Pub/Sub as a transport. We secure access to Pub/Sub from Azure utilising DefaultAzureCredential identities on Azure which are exchanged for GCP Credentials via WIF (Workload identity federation).

With the current PubSub transport setup it's not possible to set the credentials or override other API settings as necessary. This PR aims to address this.

Summary

The GCP Pub/Sub transport currently hard-codes its client construction — only EmulatorDetection is configurable. There is no way to inject credentials or customise the underlying GCP client builders, which blocks cross-cloud authentication scenarios (e.g. an application running on Azure App Service or Azure Container Apps authenticating to GCP Pub/Sub via Workload Identity Federation).

This PR adds:

  • ConfigurePublisherApiClient(Action<PublisherServiceApiClientBuilder>) / (Func<PublisherServiceApiClientBuilder, ValueTask>) — async-capable callback applied to the publisher API client builder before BuildAsync(), after EmulatorDetection is set (so callbacks can override transport-level defaults). Multiple calls compose in order.
  • ConfigureSubscriberApiClient — same, for the subscriber API client builder used for topic/subscription management.
  • ConfigureSubscriberClient — same, for the SubscriberClientBuilder used by each streaming listener (BatchedPubsubListener and InlinePubsubListener).
  • UseCredential(GoogleCredential) — convenience shorthand that sets GoogleCredential on all three builders. GoogleCredential manages its own token refresh lifecycle, including Workload Identity Federation scenarios, so no background refresh task is needed in the application.
  • UseCredential(Func<ValueTask<GoogleCredential>>) — async overload for when the credential itself must be fetched asynchronously at startup (e.g. reading from Azure Key Vault).

All callbacks and UseCredential are on PubsubConfiguration (the fluent builder returned by UsePubsub()), consistent with how other Wolverine transports expose connection configuration (Azure Service Bus TokenCredential, Kafka Action<ProducerBuilder>, etc.).

Document updates

A new Customisation page has been added under the Google PubSub section (docs/guide/messaging/transports/gcp-pubsub/customisation.md) covering:

  • UseCredential for WIF/file-based credentials, including a worked Azure Container Apps example showing how to construct a URL-sourced external account credential from ACA's managed identity environment variables
  • The async UseCredential(Func<ValueTask<GoogleCredential>>) overload for credentials that must be fetched at startup
  • ConfigurePublisherApiClient, ConfigureSubscriberApiClient, and ConfigureSubscriberClient with a reference table and examples for custom endpoints and flow control settings

The existing Connecting to the Broker section on the index page has a new authentication sub-section summarising UseCredential with a link through to the Customisation page for deeper configuration. The Customisation page has also been added to the sidebar nav.

Tests

A new PubsubConfigurationTests class covers:

  • Unit tests (no emulator required) — verifying that each Configure* method sets the correct callback on the transport, that multiple calls compose in order, that async callbacks are properly awaited, and that UseCredential (both sync and async factory overloads) threads the credential through to all three builders via a second capture callback.
  • Integration test (configure_callbacks_are_applied_to_live_builders, requires docker compose up -d gcp-pubsub) — sets EmulatorDetection.ProductionOnly at the transport level, then overrides to EmulatorOnly exclusively via the three Configure* callbacks. StartAsync succeeding (via Should.NotThrowAsync) proves all three callbacks were applied to the real builders; AutoProvision makes live API calls during startup and listener initialisation is awaited, so any misconfiguration surfaces as a thrown exception.

…e API clients at once. Particularly useful when working in cross-cloud scenarios where you might be constructing a GoogleCredential via WIF (Workload Identiy Federation) from another cloud provider.
@bittercoder bittercoder changed the title feat(gcp-pubsub): configurable client builders and credential injection Configurable client builders and credential injection Jun 22, 2026
@jeremydmiller
jeremydmiller merged commit b687206 into JasperFx:main Jun 22, 2026
24 checks passed
jeremydmiller added a commit that referenced this pull request Jun 22, 2026
… GCP Pub/Sub (#3195)

Follow-up to #3172. Documentation and test-only additions:

- Docs: clarify that the UseCredential async factory is re-invoked on every
  listener (re)connect (not once at startup), and add a "Rolling credentials"
  section with a thread-safe RollingCredentialSource sample (cache + refresh
  margin + double-checked locking) for short-lived/rotated tokens.
- Tests: round out unit-test symmetry across all three Configure* hooks
  (compose-in-order, async-await, async credential factory) and add two tests
  that lock in the rolling semantics (factory re-invoked per connect; fresh
  credential instance per connect).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 23, 2026
This was referenced Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants