Support GAPIC unary operations and configurable TLS - #7
Merged
Merged
Conversation
This was referenced Sep 24, 2026
samuel-williams-shopify
marked this pull request as ready for review
September 24, 2026 04:09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GAPIC unary calls need deferred operations and authentication callbacks, while Google/proxy responses expose content-type, metadata, and HTTP-response handling failures. Add
return_op: trueoperations with execution, deadlines, cancellation, status, and response metadata, plusClientStub.for(Service)and an optionalGapicServiceStubadapter for generated unary clients.Support
Compatible::ChannelCredentials.new(root_certificates, private_key, certificate_chain)with grpc-ruby's positional PEM arguments. TheChannelCredentialsmodule provides a factory that returnsIO::Endpoint::TLS::Configurationdirectly, so the stub needs no credential wrapper handling. Preserve custom trust roots and client certificate chains; omitted roots use the transport's default trust store, and gRPC-specific root overrides must be supplied explicitly. Peer and hostname verification are enabled by default, including localhost. Explicit target schemes must match the credentials. Native gRPC credential objects are rejected because their TLS material and composed callbacks cannot be recovered through Ruby's public API. Existing callers can useCompatible::ChannelCredentials.newwith the original PEM inputs; no process-wide GRPC constants are replaced.Authentication callbacks run on each execution with the service's
:jwt_aud_uri, derived from the actual channel endpoint. Merge their returned authentication headers into request metadata and keep the authentication context out of HTTP headers. Support original Google credential objects throughupdater_proc, and reject callbacks on plaintext channels or shared clients whose endpoint is unknown. The adapter preserves original credentials at GAPIC's stub-construction boundary; documentation includes a KMS example and custom TLS configuration.Requests use
application/grpc, and binary metadata uses the shared protocol decoder. Map nativeAsync::GRPC::ResponseErrorto grpc-ruby errors using the HTTP status, retaining the cause and its buffered response. Callers can inspecterror.cause.responseand readerror.cause.response.readfor diagnostics.Unit tests cover TLS argument mapping, certificate bundle ordering, incomplete identities, operation state, cancellation cleanup, thread boundaries, and GAPIC channel ownership. HTTP/2 integration tests exercise GAPIC with real Google JWT credentials and verify the signature and audience. Local TLS tests cover custom roots, hostname verification, and mutual authentication, including a GAPIC call using mapped gRPC client credentials and rejection of untrusted servers and missing client certificates.
Fixes #2.
Fixes #3.
Fixes #4.
Fixes #6.
Transport-error translation in #5 remains separate work. Socket and TLS failures can still raise native Ruby exceptions. Supported RPC scope is unary; active cancellation runs in the same Async reactor. Native GAPIC channel pools, interceptors, and additional native operation controls remain unsupported.
Requires released
async-grpc ~> 0.10,async-http ~> 0.100, andio-endpoint ~> 0.18. The existing optional sibling-checkout preference remains available for local development.Validation:
COVERAGE=PartialSummary bundle exec bake test(99 tests, 344 assertions; 275/275 lines executed),bundle exec rubocop(26 files), andbundle exec bake decode:index:coverage lib(28/28 public definitions). Tested on Ruby 4.0.7 against published async-grpc 0.10.0, protocol-grpc 0.16.0, async-http 0.105.0, and io-endpoint 0.18.0 in an isolated checkout. Tests generate local credentials and certificates; no live Google services or production credentials are used.