Skip to content

Commit d95e762

Browse files
authored
PHPLIB-1071: Do not create ECC collection and check wire version for QEv2 (#1084)
* Sync spec tests for QEv2 without ECC collection Synced to mongodb/specifications@eb3d882 * Check for omitted fields at any level of observed commands The original logic in the Transactions legacy test runner only handled assertions for top-level fields. This adds logic to check fields within embedded documents, as needed by the CSFLE tests. * Remove ecc collection from CreateEncryptedCollection and DropEncryptedCollection * Check wire version for Queryable Encryption support in CreateEncryptedCollection
1 parent 7f0b902 commit d95e762

File tree

79 files changed

+617
-855
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+617
-855
lines changed

src/Database.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ public function createCollection(string $collectionName, array $options = [])
313313
* @return array A tuple containing the command result document from creating the collection and the modified "encryptedFields" option
314314
* @throws InvalidArgumentException for parameter/option parsing errors
315315
* @throws CreateEncryptedCollectionException for any errors creating data keys or creating the collection
316+
* @throws UnsupportedException if Queryable Encryption is not supported by the selected server
316317
*/
317318
public function createEncryptedCollection(string $collectionName, ClientEncryption $clientEncryption, string $kmsProvider, ?array $masterKey, array $options): array
318319
{

src/Operation/CreateEncryptedCollection.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
2323
use MongoDB\Driver\Server;
2424
use MongoDB\Exception\InvalidArgumentException;
25+
use MongoDB\Exception\UnsupportedException;
2526

2627
use function array_key_exists;
2728
use function is_array;
2829
use function is_object;
30+
use function MongoDB\server_supports_feature;
2931

3032
/**
3133
* Create an encrypted collection.
@@ -44,6 +46,9 @@
4446
*/
4547
class CreateEncryptedCollection implements Executable
4648
{
49+
/** @var integer */
50+
private static $wireVersionForQueryableEncryptionV2 = 21;
51+
4752
/** @var CreateCollection */
4853
private $createCollection;
4954

@@ -81,13 +86,12 @@ public function __construct(string $databaseName, string $collectionName, array
8186

8287
$this->createCollection = new CreateCollection($databaseName, $collectionName, $options);
8388

84-
/** @psalm-var array{eccCollection?: ?string, ecocCollection?: ?string, escCollection?: ?string} */
89+
/** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */
8590
$encryptedFields = (array) $options['encryptedFields'];
8691
$enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]];
8792

8893
$this->createMetadataCollections = [
8994
new CreateCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc', $enxcolOptions),
90-
new CreateCollection($databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc', $enxcolOptions),
9195
new CreateCollection($databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc', $enxcolOptions),
9296
];
9397

@@ -150,9 +154,14 @@ public function createDataKeys(ClientEncryption $clientEncryption, string $kmsPr
150154
* @see Executable::execute()
151155
* @return array|object Command result document from creating the encrypted collection
152156
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
157+
* @throws UnsupportedException if the server does not support Queryable Encryption
153158
*/
154159
public function execute(Server $server)
155160
{
161+
if (! server_supports_feature($server, self::$wireVersionForQueryableEncryptionV2)) {
162+
throw new UnsupportedException('Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.');
163+
}
164+
156165
foreach ($this->createMetadataCollections as $createMetadataCollection) {
157166
$createMetadataCollection->execute($server);
158167
}

src/Operation/DropEncryptedCollection.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,11 @@ public function __construct(string $databaseName, string $collectionName, array
7171
throw InvalidArgumentException::invalidType('"encryptedFields" option', $options['encryptedFields'], ['array', 'object']);
7272
}
7373

74-
/** @psalm-var array{eccCollection?: ?string, ecocCollection?: ?string, escCollection?: ?string} */
74+
/** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */
7575
$encryptedFields = (array) $options['encryptedFields'];
7676

7777
$this->dropMetadataCollections = [
7878
new DropCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'),
79-
new DropCollection($databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'),
8079
new DropCollection($databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'),
8180
];
8281

tests/SpecTests/ClientSideEncryptionSpecTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,15 @@ public function setUp(): void
278278
/**
279279
* Assert that the expected and actual command documents match.
280280
*
281+
* Note: this method may modify the $expected object.
282+
*
281283
* @param stdClass $expected Expected command document
282284
* @param stdClass $actual Actual command document
283285
*/
284286
public static function assertCommandMatches(stdClass $expected, stdClass $actual): void
285287
{
288+
static::assertCommandOmittedFields($expected, $actual);
289+
286290
static::assertDocumentsMatch($expected, $actual);
287291
}
288292

tests/SpecTests/FunctionalTestCase.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use function json_encode;
1717
use function MongoDB\BSON\fromJSON;
1818
use function MongoDB\BSON\toPHP;
19+
use function property_exists;
1920
use function sprintf;
2021
use function version_compare;
2122

@@ -95,6 +96,28 @@ public static function assertDocumentsMatch($expectedDocument, $actualDocument,
9596
static::assertThat($actualDocument, $constraint, $message);
9697
}
9798

99+
/**
100+
* Assert omitted fields in command documents.
101+
*
102+
* Note: this method may modify the $expected object.
103+
*
104+
* @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#null-values
105+
*/
106+
protected static function assertCommandOmittedFields(stdClass $expected, stdClass $actual): void
107+
{
108+
foreach ($expected as $key => $value) {
109+
if ($value === null) {
110+
static::assertObjectNotHasAttribute($key, $actual);
111+
unset($expected->{$key});
112+
continue;
113+
}
114+
115+
if ($value instanceof stdClass && property_exists($actual, $key) && $actual->{$key} instanceof stdClass) {
116+
static::assertCommandOmittedFields($value, $actual->{$key});
117+
}
118+
}
119+
}
120+
98121
/**
99122
* Assert data within the outcome collection.
100123
*/

tests/SpecTests/TransactionsSpecTest.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public function tearDown(): void
6262
*
6363
* Note: this method may modify the $expected object.
6464
*
65+
* @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#command-started-events
6566
* @param stdClass $expected Expected command document
6667
* @param stdClass $actual Actual command document
6768
*/
@@ -100,12 +101,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual
100101
* preferable to skipping the txnNumber assertion. */
101102
//unset($expected['txnNumber']);
102103

103-
foreach ($expected as $key => $value) {
104-
if ($value === null) {
105-
static::assertObjectNotHasAttribute($key, $actual);
106-
unset($expected->{$key});
107-
}
108-
}
104+
static::assertCommandOmittedFields($expected, $actual);
109105

110106
static::assertDocumentsMatch($expected, $actual);
111107
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedDate",
11+
"bsonType": "date",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
},
20+
"min": {
21+
"$date": {
22+
"$numberLong": "0"
23+
}
24+
},
25+
"max": {
26+
"$date": {
27+
"$numberLong": "200"
28+
}
29+
}
30+
}
31+
}
32+
]
33+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedDecimal",
11+
"bsonType": "decimal",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
}
20+
}
21+
}
22+
]
23+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedDecimalPrecision",
11+
"bsonType": "decimal",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
},
20+
"min": {
21+
"$numberDecimal": "0.0"
22+
},
23+
"max": {
24+
"$numberDecimal": "200.0"
25+
},
26+
"precision": {
27+
"$numberInt": "2"
28+
}
29+
}
30+
}
31+
]
32+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedDouble",
11+
"bsonType": "double",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
}
20+
}
21+
}
22+
]
23+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedDoublePrecision",
11+
"bsonType": "double",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
},
20+
"min": {
21+
"$numberDouble": "0.0"
22+
},
23+
"max": {
24+
"$numberDouble": "200.0"
25+
},
26+
"precision": {
27+
"$numberInt": "2"
28+
}
29+
}
30+
}
31+
]
32+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedInt",
11+
"bsonType": "int",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
},
20+
"min": {
21+
"$numberInt": "0"
22+
},
23+
"max": {
24+
"$numberInt": "200"
25+
}
26+
}
27+
}
28+
]
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"fields": [
3+
{
4+
"keyId": {
5+
"$binary": {
6+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
7+
"subType": "04"
8+
}
9+
},
10+
"path": "encryptedLong",
11+
"bsonType": "long",
12+
"queries": {
13+
"queryType": "rangePreview",
14+
"contention": {
15+
"$numberLong": "0"
16+
},
17+
"sparsity": {
18+
"$numberLong": "1"
19+
},
20+
"min": {
21+
"$numberLong": "0"
22+
},
23+
"max": {
24+
"$numberLong": "200"
25+
}
26+
}
27+
}
28+
]
29+
}

tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
{
2-
"escCollection": "enxcol_.default.esc",
3-
"eccCollection": "enxcol_.default.ecc",
4-
"ecocCollection": "enxcol_.default.ecoc",
52
"fields": [
63
{
74
"keyId": {
@@ -30,4 +27,4 @@
3027
"bsonType": "string"
3128
}
3229
]
33-
}
30+
}

0 commit comments

Comments
 (0)