Skip to content

Commit 06825ce

Browse files
chore: add PQC conformance tests (#9299)
1 parent 587ff13 commit 06825ce

5 files changed

Lines changed: 83 additions & 14 deletions

File tree

.github/workflows/conformance-tests-gax-showcase.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
gapic-showcase:
1111
runs-on: ubuntu-latest
1212
env:
13-
GAPIC_SHOWCASE_VERSION: 0.36.2
13+
GAPIC_SHOWCASE_VERSION: 0.42.0
1414
OS: linux
1515
ARCH: amd64
1616
name: GAPIC Showcase Conformance Tests
@@ -21,18 +21,18 @@ jobs:
2121
- name: Setup PHP
2222
uses: shivammathur/setup-php@v2
2323
with:
24-
php-version: '8.1'
25-
extensions: grpc
24+
php-version: '8.2'
25+
extensions: grpc-1.83.0
2626

2727
- name: Install and run GAPIC Showcase
2828
run: |
2929
curl -L https://github.com/googleapis/gapic-showcase/releases/download/v${GAPIC_SHOWCASE_VERSION}/gapic-showcase-${GAPIC_SHOWCASE_VERSION}-${OS}-${ARCH}.tar.gz | tar -zx
30-
./gapic-showcase run &
30+
./gapic-showcase run --port :7469 --tls --ca-cert-output-file Gax/tests/Conformance/showcase.pem &
31+
sleep 2
3132
3233
- name: Install dependencies
3334
run: |
3435
composer update --prefer-dist --no-interaction --no-suggest -d Gax/
3536
3637
- name: Run PHPUnit
3738
run: Gax/vendor/bin/phpunit -c Gax/phpunit-conformance.xml.dist
38-

Gax/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ src/Jison/Parser.js
2020

2121
# VS Code
2222
.vscode
23+
24+
*.pem

Gax/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ be found for Mac or Windows.
8888
> phpstan -c phpstan.neon.dist
8989
```
9090

91+
9192
## License
9293

9394
BSD - See [LICENSE][] for more information.

Gax/tests/Conformance/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ Options:
2727

2828
## Running Conformance Tests
2929

30-
1. Install and launch the matching `gapic-showcase` mock server in the background:
30+
1. Install and launch the matching `gapic-showcase` mock server (with Auto-TLS enabled for PQC tests):
3131
```sh
3232
# Option 1 (curl)
33-
curl -L https://github.com/googleapis/gapic-showcase/releases/download/v0.41.1/gapic-showcase-0.41.1-linux-amd64.tar.gz | tar -zx
34-
./gapic-showcase run &
33+
curl -L https://github.com/googleapis/gapic-showcase/releases/download/v0.42.0/gapic-showcase-0.42.0-linux-amd64.tar.gz | tar -zx
34+
./gapic-showcase run --port :7469 --tls --ca-cert-output-file Gax/tests/Conformance/showcase.pem &
3535

3636
# Option 2 (go install)
3737
go install github.com/googleapis/gapic-showcase/cmd/gapic-showcase@latest
38-
gapic-showcase run &
38+
gapic-showcase run --port :7469 --tls --ca-cert-output-file Gax/tests/Conformance/showcase.pem &
3939
```
4040

4141
2. Run the PHPUnit conformance test suite:

Gax/tests/Conformance/ShowcaseTest.php

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,51 @@
2323
use Google\ApiCore\KnownTypes;
2424
use Google\ApiCore\InsecureCredentialsWrapper;
2525
use Google\ApiCore\InsecureRequestBuilder;
26+
use Google\ApiCore\RequestBuilder;
2627
use Google\ApiCore\Transport\GrpcTransport;
2728
use Google\ApiCore\Transport\TransportInterface;
2829
use Google\ApiCore\Transport\RestTransport;
2930
use Google\Auth\HttpHandler\HttpHandlerFactory;
3031
use Google\Protobuf\Internal\Message;
3132
use Google\Showcase\V1beta1\Client\EchoClient;
33+
use Google\Showcase\V1beta1\EchoRequest;
3234
use Google\Showcase\V1beta1\FailEchoWithDetailsRequest;
3335
use Grpc\ChannelCredentials;
36+
use GuzzleHttp\Client;
3437

3538
final class ShowcaseTest extends TestCase
3639
{
40+
private const TLS_GROUP = 'x-showcase-tls-group';
41+
private const PEM_PATH = __DIR__ . '/showcase.pem';
42+
3743
public function provideTransport()
3844
{
45+
$host = 'localhost:7469';
46+
$restConfigPath = __DIR__ . '/src/V1beta1/resources/echo_rest_client_config.php';
47+
48+
if (file_exists(self::PEM_PATH)) {
49+
$pemContents = file_get_contents(self::PEM_PATH);
50+
$grpcCredentials = ChannelCredentials::createSsl($pemContents);
51+
$requestBuilder = new RequestBuilder($host, $restConfigPath);
52+
$guzzleClient = new Client(['verify' => self::PEM_PATH]);
53+
} else {
54+
$grpcCredentials = ChannelCredentials::createInsecure();
55+
$requestBuilder = new InsecureRequestBuilder($host, $restConfigPath);
56+
$guzzleClient = null;
57+
}
58+
3959
// build gRPC transport
4060
$grpc = GrpcTransport::build(
41-
'localhost:7469',
42-
['stubOpts' => ['credentials' => ChannelCredentials::createInsecure()]]
61+
$host,
62+
[
63+
'stubOpts' => [
64+
'credentials' => $grpcCredentials
65+
]
66+
]
4367
);
4468

4569
// build REST transport
46-
$restConfigPath = __DIR__ . '/src/V1beta1/resources/echo_rest_client_config.php';
47-
$requestBuilder = new InsecureRequestBuilder('localhost:7469', $restConfigPath);
48-
$httpHandler = HttpHandlerFactory::build();
70+
$httpHandler = HttpHandlerFactory::build($guzzleClient);
4971
$rest = new RestTransport($requestBuilder, [$httpHandler, 'async']);
5072

5173
return [[$grpc], [$rest]];
@@ -71,4 +93,48 @@ public function testFailWithDetails(TransportInterface $transport): void
7193
$this->assertInstanceOf(Message::class, $detail);
7294
}
7395
}
96+
97+
/** @dataProvider provideTransport */
98+
public function testPqc(TransportInterface $transport): void
99+
{
100+
if (!file_exists(self::PEM_PATH)) {
101+
$this->markTestSkipped(
102+
'You need to run the showcase server with --tls ' .
103+
'--ca-cert-output-file tests/Conformance/showcase.pem to run PQC tests'
104+
);
105+
}
106+
107+
$expected = 'This is a test';
108+
$expectedGroup = 'X25519MLKEM768';
109+
$responseHeaders = null;
110+
$metadataCallback = function (array $metadata) use (&$responseHeaders) {
111+
$responseHeaders = $metadata;
112+
};
113+
114+
$echoClient = new EchoClient([
115+
'credentials' => new InsecureCredentialsWrapper(),
116+
'transport' => $transport
117+
]);
118+
119+
$echoRequest = new EchoRequest();
120+
$echoRequest->setContent($expected);
121+
$response = $echoClient->echo($echoRequest, [
122+
'metadataCallback' => $metadataCallback
123+
]);
124+
125+
$this->assertEquals($expected, $response->getContent());
126+
$this->assertNotNull($responseHeaders);
127+
128+
/** @var array<string, array<int, string>> $responseHeaders */
129+
$responseHeaders = array_change_key_case($responseHeaders, CASE_LOWER);
130+
$negotiatedGroup = $responseHeaders[self::TLS_GROUP][0];
131+
132+
if ($transport instanceof GrpcTransport) {
133+
// gRPC must ALWAYS negotiate PQC
134+
$this->assertEquals($expectedGroup, $negotiatedGroup);
135+
} else {
136+
// REST uses host system OpenSSL (X25519MLKEM768 when PQC is available, or X25519 fallback)
137+
$this->assertContains($negotiatedGroup, [$expectedGroup, 'X25519']);
138+
}
139+
}
74140
}

0 commit comments

Comments
 (0)