test: add post-quantum cryptography conformance tests for showcase - #1351
Draft
torreypayne wants to merge 2 commits into
Draft
torreypayne wants to merge 2 commits into
torreypayne wants to merge 2 commits into
Conversation
Adds a dedicated suite that proves the generated Ruby clients negotiate X25519MLKEM768 with the Showcase server over both transports. Assertions read the TLS metadata that Showcase reflects onto every response (x-showcase-tls-group and x-showcase-tls-client-supported-groups) rather than inspecting CRuby's internal OpenSSL structures, whose layout is not stable across Ruby releases or platforms. Covered scenarios: - gRPC and REST negotiate the hybrid post-quantum group. - gRPC and REST advertise the group in their ClientHello. - Both transports degrade cleanly to classical X25519 when the server offers only classical groups, confirming no hard post-quantum dependency. - gRPC completes the handshake when the server accepts nothing but post-quantum key exchange. REST coverage is skipped when the host OpenSSL predates 3.5, which is the first release to implement ML-KEM.
This was referenced Sep 15, 2026
The REST post-quantum assertion was guarded by a skip whenever the host OpenSSL was below 3.5. GitHub Actions ubuntu-latest ships OpenSSL 3.0.13, so in practice that guard meant the REST transport was never exercised in CI at all: a permanently green check that verified nothing. Replace the skip with an assertion that carries signal on every host. The negotiated group must be present, which proves the connection was really TLS; it must be either X25519MLKEM768 or classical X25519; and it must be a group the client actually offered in its ClientHello. A plaintext connection, or any unexpected group, still fails. Setting SHOWCASE_REQUIRE_REST_PQC=1 promotes this into a strict post-quantum assertion, for environments guaranteed to provide OpenSSL >= 3.5. This mirrors the merged conformance test in gax-php. Ruby and PHP are the only Cloud SDK languages whose REST transport binds to the system OpenSSL instead of a vendored TLS stack, so they are the only two that cannot hard-assert post-quantum key exchange on a stock runner.
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.
Adds
shared/test/showcase/pqc_test.rb, a dedicated suite proving that generated Ruby clients negotiateX25519MLKEM768with the Showcase server over both transports.How it verifies PQC
Ruby never performs the key exchange itself — gRPC delegates to the BoringSSL build vendored in the
grpcgem, and REST delegates to the system OpenSSL thatNet::HTTPlinks against. The suite therefore asserts on what the server observed, via the metadata Showcase reflects onto every response:x-showcase-tls-group— the group that was negotiatedx-showcase-tls-client-supported-groups— everything the client offered in itsClientHelloThis is the same mechanism Python, Node, Java, C#, and C++ already use, so Ruby's assertions are directly comparable to the rest of the ecosystem.
Scenarios covered
test_grpc_negotiates_post_quantum_key_exchangeX25519MLKEM768and advertised it inClientHellotest_rest_negotiates_post_quantum_key_exchangeX25519MLKEM768and advertised it inClientHellotest_grpc_connects_when_server_requires_post_quantum_key_exchange--tls-groups 0x11ectest_grpc_falls_back_to_classical_key_exchangeX25519against--tls-groups 0x001d,0x0017test_rest_falls_back_to_classical_key_exchangeX25519against--tls-groups 0x001d,0x0017The fallback tests matter as much as the happy path: they prove we did not introduce a hard post-quantum dependency that would break clients talking to classical-only endpoints.
Notes for reviewers
normalize_headersfails loudly if the TLS metadata is absent. Without that guard a non-TLS connection would silently turn every assertion into a no-op.opensslis a default gem binding to the hostlibssl, and ML-KEM needs OpenSSL >= 3.5 — which no runner available to us provides (ubuntu-latestis 3.0.13). Guarding with askipwould mean the REST transport is never exercised at all, i.e. a permanently green check that proves nothing. Instead the test always runs and asserts the negotiated group against a{X25519MLKEM768, X25519}allowlist, cross-checking that the group was actually offered in theClientHello; plaintext or any unexpected curve still fails. SettingSHOWCASE_REQUIRE_REST_PQC=1tightens this to an exactX25519MLKEM768match, which chore(ci): hard-assert REST post-quantum key exchange on an OpenSSL 3.5 image #1352 runs in CI. This mirrors the merged gax-php conformance test, the one other language with the same constraint.--tls-groupsservers reuse the harness certificate and are reaped in anensureblock.Stack
This is a stacked PR. Each branch targets its predecessor, so the diff here contains only the commits unique to this step. Review and merge bottom-up.
bump-showcase→mainchore:GAPIC_SHOWCASE_VERSIONto0.44.0pqc-tls-validation→bump-showcasetest:pqc-validation-tests→pqc-tls-validationtest:pqc_test.rb; tolerant REST assertion (Layer 1)pqc-rest-ci→pqc-validation-testschore(ci):Companion PR — independent, different repository, not part of this stack:
googleapis/ruby-core-libraries#73 —
fix:raise thegapic-commonfloor togrpc ">= 1.83", "< 2.a". This is the only customer-facing change in the effort and the only one that triggers a gem release.Design: go/sdk:ruby-pqc · Parent (approved): go/cloudsdk-pqc-ruby
Pre-Flight Engineering Audit Sign-Off
ShowcaseTest.instance_variable_get :@showcase_dir, per the team'sinstance_variable_getconvention.wait_for_showcaseprobe (explicit monotonic deadline) and reaped viaProcess.kill+Process.waitinsideensure. No orphaned processes, no baresleepused as synchronization.Fiddleprobe that dereferenced a hardcoded struct offset and asserted nothing.toys test showcasegreen across four environments spanning the OpenSSL range, with zero skips in every one: host Ruby 4.0.5 / OpenSSL 3.6.3 (tolerant and strict),ruby:3.2-trixie/ 3.5.5 (strict), andruby:3.2-bookworm/ 3.0.18 (tolerant). The bookworm run is the important one — it carries the same OpenSSL generation asubuntu-latest, and the REST test now runs and passes there via the classical-fallback branch instead of skipping.git diff origin/maintouches onlypqc_test.rbandtest_helper.rb; noGemfile.lockdrift, and thefiddlegem added by the earlier draft is gone.