@proteinjs/db-driver-spanner 1.23.5 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/generated/test/index.d.ts.map +1 -1
  3. package/dist/generated/test/index.js +15 -1
  4. package/dist/generated/test/index.js.map +1 -1
  5. package/dist/src/SpannerSchemaOperations.d.ts.map +1 -1
  6. package/dist/src/SpannerSchemaOperations.js +4 -1
  7. package/dist/src/SpannerSchemaOperations.js.map +1 -1
  8. package/dist/test/ColumnEncryption.test.d.ts +2 -0
  9. package/dist/test/ColumnEncryption.test.d.ts.map +1 -0
  10. package/dist/test/ColumnEncryption.test.js +482 -0
  11. package/dist/test/ColumnEncryption.test.js.map +1 -0
  12. package/dist/test/EncryptedSearch.test.d.ts +2 -0
  13. package/dist/test/EncryptedSearch.test.d.ts.map +1 -0
  14. package/dist/test/EncryptedSearch.test.js +455 -0
  15. package/dist/test/EncryptedSearch.test.js.map +1 -0
  16. package/dist/test/EncryptionLifecycleWalker.test.d.ts +2 -0
  17. package/dist/test/EncryptionLifecycleWalker.test.d.ts.map +1 -0
  18. package/dist/test/EncryptionLifecycleWalker.test.js +408 -0
  19. package/dist/test/EncryptionLifecycleWalker.test.js.map +1 -0
  20. package/dist/test/EncryptionPerf.test.d.ts +2 -0
  21. package/dist/test/EncryptionPerf.test.d.ts.map +1 -0
  22. package/dist/test/EncryptionPerf.test.js +278 -0
  23. package/dist/test/EncryptionPerf.test.js.map +1 -0
  24. package/dist/test/EncryptionSortAndUnique.test.d.ts +2 -0
  25. package/dist/test/EncryptionSortAndUnique.test.d.ts.map +1 -0
  26. package/dist/test/EncryptionSortAndUnique.test.js +229 -0
  27. package/dist/test/EncryptionSortAndUnique.test.js.map +1 -0
  28. package/dist/test/index.d.ts +1 -0
  29. package/dist/test/index.d.ts.map +1 -1
  30. package/dist/test/index.js +1 -0
  31. package/dist/test/index.js.map +1 -1
  32. package/dist/test/util/columnEncryptionTestHarness.d.ts +23 -0
  33. package/dist/test/util/columnEncryptionTestHarness.d.ts.map +1 -0
  34. package/dist/test/util/columnEncryptionTestHarness.js +136 -0
  35. package/dist/test/util/columnEncryptionTestHarness.js.map +1 -0
  36. package/dist/test/util/columnEncryptionTestTables.d.ts +75 -0
  37. package/dist/test/util/columnEncryptionTestTables.d.ts.map +1 -0
  38. package/dist/test/util/columnEncryptionTestTables.js +124 -0
  39. package/dist/test/util/columnEncryptionTestTables.js.map +1 -0
  40. package/dist/test/util/serviceUpdateVerbsTestTables.d.ts +2 -2
  41. package/generated/test/index.ts +15 -1
  42. package/package.json +6 -6
  43. package/src/SpannerSchemaOperations.ts +4 -1
  44. package/test/ColumnEncryption.test.ts +252 -0
  45. package/test/EncryptedSearch.test.ts +247 -0
  46. package/test/EncryptionLifecycleWalker.test.ts +223 -0
  47. package/test/EncryptionPerf.test.ts +156 -0
  48. package/test/EncryptionSortAndUnique.test.ts +130 -0
  49. package/test/index.ts +1 -0
  50. package/test/util/columnEncryptionTestHarness.ts +54 -0
  51. package/test/util/columnEncryptionTestTables.ts +115 -0
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ var db_1 = require("@proteinjs/db");
40
+ var db_driver_spanner_1 = require("@proteinjs/db-driver-spanner");
41
+ var db_transaction_context_1 = require("@proteinjs/db-transaction-context");
42
+ var getDropTestTable_1 = require("./util/getDropTestTable");
43
+ var SpannerEmulatorProvisioner_1 = require("./util/SpannerEmulatorProvisioner");
44
+ var columnEncryptionTestTables_1 = require("./util/columnEncryptionTestTables");
45
+ var columnEncryptionTestHarness_1 = require("./util/columnEncryptionTestHarness");
46
+ var test_1 = require("@proteinjs/db/test");
47
+ require("../generated/test/index");
48
+ var spannerDriver = new db_driver_spanner_1.SpannerDriver({
49
+ projectId: 'proteinjs-test',
50
+ instanceName: 'proteinjs-test',
51
+ databaseName: 'test',
52
+ });
53
+ globalThis['__proteinjs_db_defaultDbDriver'] = spannerDriver;
54
+ var OWNER = 'enc-perf-owner-a';
55
+ var ROW_COUNT = 1000;
56
+ var encTable = new columnEncryptionTestTables_1.EncPerfRowTable();
57
+ var plainTable = new columnEncryptionTestTables_1.PlainPerfRowTable();
58
+ var db = new db_1.Db(spannerDriver, undefined, new db_transaction_context_1.TransactionContext());
59
+ /**
60
+ * Performance sanity for the doc's claims (TRUST_AND_COMPLIANCE §1.5): per-value AES-256-GCM
61
+ * decrypt ~1-3µs in Node; a 1k-row read's decrypt overhead an order of magnitude below the
62
+ * database/network latency the read already pays. Numbers are printed for the report.
63
+ */
64
+ describe('Column encryption performance sanity', function () {
65
+ var dropTable = (0, getDropTestTable_1.getDropTestTable)(spannerDriver);
66
+ var tableManager = spannerDriver.getTableManager();
67
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
68
+ var body, _loop_1, batch;
69
+ return __generator(this, function (_a) {
70
+ switch (_a.label) {
71
+ case 0: return [4 /*yield*/, SpannerEmulatorProvisioner_1.SpannerEmulatorProvisioner.ensureProvisioned({
72
+ projectId: 'proteinjs-test',
73
+ instanceName: 'proteinjs-test',
74
+ databaseName: 'test',
75
+ })];
76
+ case 1:
77
+ _a.sent();
78
+ (0, test_1.registerTestUser)();
79
+ (0, db_1.setDbEncryptionConfig)({
80
+ masterKeyProvider: new db_1.InMemoryMasterKeyProvider('column-encryption-test'),
81
+ getAccessibleKeyOwners: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
82
+ return [2 /*return*/, [OWNER]];
83
+ }); }); },
84
+ });
85
+ return [4 /*yield*/, (0, columnEncryptionTestHarness_1.loadColumnEncryptionTestSchema)(tableManager, [encTable, plainTable])];
86
+ case 2:
87
+ _a.sent();
88
+ return [4 /*yield*/, (0, columnEncryptionTestHarness_1.purgeColumnEncryptionTestRows)(spannerDriver, [encTable, plainTable])];
89
+ case 3:
90
+ _a.sent();
91
+ body = function (index) {
92
+ return "note body ".concat(index, " \u2014 a sentence of ordinary length, the kind a document row actually stores in practice.");
93
+ };
94
+ _loop_1 = function (batch) {
95
+ return __generator(this, function (_b) {
96
+ switch (_b.label) {
97
+ case 0: return [4 /*yield*/, db.runTransaction(function () { return __awaiter(void 0, void 0, void 0, function () {
98
+ var i, index;
99
+ return __generator(this, function (_a) {
100
+ switch (_a.label) {
101
+ case 0:
102
+ i = 0;
103
+ _a.label = 1;
104
+ case 1:
105
+ if (!(i < 100)) return [3 /*break*/, 4];
106
+ index = batch * 100 + i;
107
+ return [4 /*yield*/, db.insert(encTable, { scope: OWNER, body: body(index) })];
108
+ case 2:
109
+ _a.sent();
110
+ _a.label = 3;
111
+ case 3:
112
+ i++;
113
+ return [3 /*break*/, 1];
114
+ case 4: return [2 /*return*/];
115
+ }
116
+ });
117
+ }); })];
118
+ case 1:
119
+ _b.sent();
120
+ return [4 /*yield*/, db.runTransaction(function () { return __awaiter(void 0, void 0, void 0, function () {
121
+ var i, index;
122
+ return __generator(this, function (_a) {
123
+ switch (_a.label) {
124
+ case 0:
125
+ i = 0;
126
+ _a.label = 1;
127
+ case 1:
128
+ if (!(i < 100)) return [3 /*break*/, 4];
129
+ index = batch * 100 + i;
130
+ return [4 /*yield*/, db.insert(plainTable, { scope: OWNER, body: body(index) })];
131
+ case 2:
132
+ _a.sent();
133
+ _a.label = 3;
134
+ case 3:
135
+ i++;
136
+ return [3 /*break*/, 1];
137
+ case 4: return [2 /*return*/];
138
+ }
139
+ });
140
+ }); })];
141
+ case 2:
142
+ _b.sent();
143
+ return [2 /*return*/];
144
+ }
145
+ });
146
+ };
147
+ batch = 0;
148
+ _a.label = 4;
149
+ case 4:
150
+ if (!(batch < ROW_COUNT / 100)) return [3 /*break*/, 7];
151
+ return [5 /*yield**/, _loop_1(batch)];
152
+ case 5:
153
+ _a.sent();
154
+ _a.label = 6;
155
+ case 6:
156
+ batch++;
157
+ return [3 /*break*/, 4];
158
+ case 7: return [2 /*return*/];
159
+ }
160
+ });
161
+ }); }, 600000);
162
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
163
+ return __generator(this, function (_a) {
164
+ switch (_a.label) {
165
+ case 0:
166
+ (0, db_1.setDbEncryptionConfig)(undefined);
167
+ (0, test_1.clearTestUser)();
168
+ return [4 /*yield*/, dropTable(encTable)];
169
+ case 1:
170
+ _a.sent();
171
+ return [4 /*yield*/, dropTable(plainTable)];
172
+ case 2:
173
+ _a.sent();
174
+ return [4 /*yield*/, SpannerEmulatorProvisioner_1.SpannerEmulatorProvisioner.release()];
175
+ case 3:
176
+ _a.sent();
177
+ return [2 /*return*/];
178
+ }
179
+ });
180
+ }); }, 120000);
181
+ var timeQuery = function (table) { return __awaiter(void 0, void 0, void 0, function () {
182
+ var start, rows, ms;
183
+ return __generator(this, function (_a) {
184
+ switch (_a.label) {
185
+ case 0:
186
+ start = process.hrtime.bigint();
187
+ return [4 /*yield*/, db.query(table, new db_1.QueryBuilder(table.name).condition({ field: 'scope', operator: '=', value: OWNER }))];
188
+ case 1:
189
+ rows = _a.sent();
190
+ ms = Number(process.hrtime.bigint() - start) / 1e6;
191
+ return [2 /*return*/, { ms: ms, rows: rows.length }];
192
+ }
193
+ });
194
+ }); };
195
+ test('1k-row read: decrypt overhead measured against the plaintext twin', function () { return __awaiter(void 0, void 0, void 0, function () {
196
+ var samples, encTotal, plainTotal, i, _a, _b, encAvg, plainAvg, overheadMs, perValueUs, encRows;
197
+ return __generator(this, function (_c) {
198
+ switch (_c.label) {
199
+ case 0:
200
+ // warm the key cache + driver sessions
201
+ return [4 /*yield*/, timeQuery(encTable)];
202
+ case 1:
203
+ // warm the key cache + driver sessions
204
+ _c.sent();
205
+ return [4 /*yield*/, timeQuery(plainTable)];
206
+ case 2:
207
+ _c.sent();
208
+ samples = 5;
209
+ encTotal = 0;
210
+ plainTotal = 0;
211
+ i = 0;
212
+ _c.label = 3;
213
+ case 3:
214
+ if (!(i < samples)) return [3 /*break*/, 7];
215
+ _a = encTotal;
216
+ return [4 /*yield*/, timeQuery(encTable)];
217
+ case 4:
218
+ encTotal = _a + (_c.sent()).ms;
219
+ _b = plainTotal;
220
+ return [4 /*yield*/, timeQuery(plainTable)];
221
+ case 5:
222
+ plainTotal = _b + (_c.sent()).ms;
223
+ _c.label = 6;
224
+ case 6:
225
+ i++;
226
+ return [3 /*break*/, 3];
227
+ case 7:
228
+ encAvg = encTotal / samples;
229
+ plainAvg = plainTotal / samples;
230
+ overheadMs = encAvg - plainAvg;
231
+ perValueUs = (overheadMs * 1000) / ROW_COUNT;
232
+ // eslint-disable-next-line no-console
233
+ console.info("[perf] 1k-row read: encrypted ".concat(encAvg.toFixed(1), "ms vs plaintext ").concat(plainAvg.toFixed(1), "ms \u2014 ") +
234
+ "decrypt overhead ".concat(overheadMs.toFixed(1), "ms total, ~").concat(perValueUs.toFixed(2), "\u00B5s/value (doc claim: ~1-3\u00B5s/value)"));
235
+ return [4 /*yield*/, db.query(encTable, new db_1.QueryBuilder(encTable.name).condition({ field: 'scope', operator: '=', value: OWNER }))];
236
+ case 8:
237
+ encRows = _c.sent();
238
+ expect(encRows.length).toBe(ROW_COUNT);
239
+ // Sanity bound, generous (emulator variance): the whole-read overhead stays well under
240
+ // the read itself — decrypt must not dominate.
241
+ expect(overheadMs).toBeLessThan(Math.max(plainAvg, 250));
242
+ return [2 /*return*/];
243
+ }
244
+ });
245
+ }); });
246
+ test('per-value decrypt microbenchmark: the in-process AES-256-GCM cost itself', function () { return __awaiter(void 0, void 0, void 0, function () {
247
+ var key, envelope, value, encrypted, iterations, i, start, i, totalUs, perValueUs;
248
+ return __generator(this, function (_a) {
249
+ switch (_a.label) {
250
+ case 0: return [4 /*yield*/, new db_1.DataKeyStore().getWriteKey(OWNER)];
251
+ case 1:
252
+ key = _a.sent();
253
+ envelope = new db_1.EncryptionEnvelope();
254
+ value = 'note body — a sentence of ordinary length, the kind a document row actually stores in practice.';
255
+ encrypted = envelope.encrypt(value, key);
256
+ iterations = 10000;
257
+ // warm
258
+ for (i = 0; i < 1000; i++) {
259
+ envelope.decrypt(encrypted, key);
260
+ }
261
+ start = process.hrtime.bigint();
262
+ for (i = 0; i < iterations; i++) {
263
+ envelope.decrypt(encrypted, key);
264
+ }
265
+ totalUs = Number(process.hrtime.bigint() - start) / 1e3;
266
+ perValueUs = totalUs / iterations;
267
+ // eslint-disable-next-line no-console
268
+ console.info("[perf] in-process decrypt: ".concat(perValueUs.toFixed(2), "\u00B5s/value over ").concat(iterations, " iterations ") +
269
+ "(doc claim: ~1-3\u00B5s/value)");
270
+ expect(envelope.decrypt(encrypted, key)).toBe(value);
271
+ // The claim's order of magnitude, with generous headroom for slow machines
272
+ expect(perValueUs).toBeLessThan(30);
273
+ return [2 /*return*/];
274
+ }
275
+ });
276
+ }); });
277
+ });
278
+ //# sourceMappingURL=EncryptionPerf.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EncryptionPerf.test.js","sourceRoot":"","sources":["../../test/EncryptionPerf.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import '../generated/test/index';
2
+ //# sourceMappingURL=EncryptionSortAndUnique.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EncryptionSortAndUnique.test.d.ts","sourceRoot":"","sources":["../../test/EncryptionSortAndUnique.test.ts"],"names":[],"mappings":"AAgBA,OAAO,yBAAyB,CAAC"}
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
+ if (ar || !(i in from)) {
41
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
+ ar[i] = from[i];
43
+ }
44
+ }
45
+ return to.concat(ar || Array.prototype.slice.call(from));
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ var db_1 = require("@proteinjs/db");
49
+ var db_driver_spanner_1 = require("@proteinjs/db-driver-spanner");
50
+ var db_transaction_context_1 = require("@proteinjs/db-transaction-context");
51
+ var getDropTestTable_1 = require("./util/getDropTestTable");
52
+ var SpannerEmulatorProvisioner_1 = require("./util/SpannerEmulatorProvisioner");
53
+ var columnEncryptionTestTables_1 = require("./util/columnEncryptionTestTables");
54
+ var columnEncryptionTestHarness_1 = require("./util/columnEncryptionTestHarness");
55
+ var test_1 = require("@proteinjs/db/test");
56
+ require("../generated/test/index");
57
+ var spannerDriver = new db_driver_spanner_1.SpannerDriver({
58
+ projectId: 'proteinjs-test',
59
+ instanceName: 'proteinjs-test',
60
+ databaseName: 'test',
61
+ });
62
+ globalThis['__proteinjs_db_defaultDbDriver'] = spannerDriver;
63
+ var OWNER_A = 'enc-sort-owner-a';
64
+ var OWNER_B = 'enc-sort-owner-b';
65
+ var sortedTable = new columnEncryptionTestTables_1.EncSortedItemTable();
66
+ var uniqueTable = new columnEncryptionTestTables_1.EncUniqueTagTable();
67
+ var db = new db_1.Db(spannerDriver, undefined, new db_transaction_context_1.TransactionContext());
68
+ /**
69
+ * The sortKey tier of the sorting story (a DECLARED bounded reveal → native ORDER BY at any
70
+ * scale), the loud live rejection without one, and value uniqueness through the equality
71
+ * fingerprint (per owner).
72
+ */
73
+ describe('Encrypted sortKey ORDER BY + fingerprint uniqueness', function () {
74
+ var dropTable = (0, getDropTestTable_1.getDropTestTable)(spannerDriver);
75
+ var tableManager = spannerDriver.getTableManager();
76
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
77
+ return __generator(this, function (_a) {
78
+ switch (_a.label) {
79
+ case 0: return [4 /*yield*/, SpannerEmulatorProvisioner_1.SpannerEmulatorProvisioner.ensureProvisioned({
80
+ projectId: 'proteinjs-test',
81
+ instanceName: 'proteinjs-test',
82
+ databaseName: 'test',
83
+ })];
84
+ case 1:
85
+ _a.sent();
86
+ (0, test_1.registerTestUser)();
87
+ (0, db_1.setDbEncryptionConfig)({
88
+ masterKeyProvider: new db_1.InMemoryMasterKeyProvider('column-encryption-test'),
89
+ getAccessibleKeyOwners: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
90
+ return [2 /*return*/, [OWNER_A]];
91
+ }); }); },
92
+ });
93
+ return [4 /*yield*/, (0, columnEncryptionTestHarness_1.loadColumnEncryptionTestSchema)(tableManager, [sortedTable, uniqueTable])];
94
+ case 2:
95
+ _a.sent();
96
+ return [4 /*yield*/, (0, columnEncryptionTestHarness_1.purgeColumnEncryptionTestRows)(spannerDriver, [sortedTable, uniqueTable])];
97
+ case 3:
98
+ _a.sent();
99
+ return [2 /*return*/];
100
+ }
101
+ });
102
+ }); }, 120000);
103
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
104
+ return __generator(this, function (_a) {
105
+ switch (_a.label) {
106
+ case 0:
107
+ (0, db_1.setDbEncryptionConfig)(undefined);
108
+ (0, test_1.clearTestUser)();
109
+ return [4 /*yield*/, dropTable(new db_1.EncryptedColumns().tokenTableFor(sortedTable))];
110
+ case 1:
111
+ _a.sent();
112
+ return [4 /*yield*/, dropTable(sortedTable)];
113
+ case 2:
114
+ _a.sent();
115
+ return [4 /*yield*/, dropTable(uniqueTable)];
116
+ case 3:
117
+ _a.sent();
118
+ return [4 /*yield*/, SpannerEmulatorProvisioner_1.SpannerEmulatorProvisioner.release()];
119
+ case 4:
120
+ _a.sent();
121
+ return [2 /*return*/];
122
+ }
123
+ });
124
+ }); }, 120000);
125
+ test('sortKey: native ORDER BY + sorted pagination over encrypted values; only the declared prefix is revealed at rest', function () { return __awaiter(void 0, void 0, void 0, function () {
126
+ var titles, ids, _i, titles_1, title, _a, _b, sorted, sortedTitles, buckets, firstPage, _c, firstPage_1, row, raw, _d, ids_1, id;
127
+ var _e;
128
+ return __generator(this, function (_f) {
129
+ switch (_f.label) {
130
+ case 0:
131
+ titles = ['banana bread', 'Apple pie', 'cherry tart', 'apricot jam', 'Blueberry scone'];
132
+ ids = [];
133
+ _i = 0, titles_1 = titles;
134
+ _f.label = 1;
135
+ case 1:
136
+ if (!(_i < titles_1.length)) return [3 /*break*/, 4];
137
+ title = titles_1[_i];
138
+ _b = (_a = ids).push;
139
+ return [4 /*yield*/, db.insert(sortedTable, { scope: OWNER_A, title: title })];
140
+ case 2:
141
+ _b.apply(_a, [(_f.sent()).id]);
142
+ _f.label = 3;
143
+ case 3:
144
+ _i++;
145
+ return [3 /*break*/, 1];
146
+ case 4: return [4 /*yield*/, db.query(sortedTable, new db_1.QueryBuilder(sortedTable.name)
147
+ .condition({ field: 'scope', operator: '=', value: OWNER_A })
148
+ .sort([{ field: 'title' }]))];
149
+ case 5:
150
+ sorted = _f.sent();
151
+ sortedTitles = sorted.map(function (row) { return row.title; });
152
+ buckets = sortedTitles.map(function (title) { return (title !== null && title !== void 0 ? title : '').toLowerCase().slice(0, 3); });
153
+ expect(buckets).toEqual(__spreadArray([], buckets, true).sort());
154
+ return [4 /*yield*/, db.query(sortedTable, new db_1.QueryBuilder(sortedTable.name)
155
+ .condition({ field: 'scope', operator: '=', value: OWNER_A })
156
+ .sort([{ field: 'title' }])
157
+ .paginate({ start: 0, end: 2 }))];
158
+ case 6:
159
+ firstPage = _f.sent();
160
+ expect(firstPage.length).toBe(2);
161
+ for (_c = 0, firstPage_1 = firstPage; _c < firstPage_1.length; _c++) {
162
+ row = firstPage_1[_c];
163
+ expect(((_e = row.title) !== null && _e !== void 0 ? _e : '').toLowerCase().slice(0, 2)).toBe('ap');
164
+ }
165
+ return [4 /*yield*/, spannerDriver.runQuery(function () { return ({
166
+ sql: "SELECT `title`, `title_enc_srt` FROM `".concat(sortedTable.name, "` WHERE `id` = '").concat(ids[0], "'"),
167
+ }); })];
168
+ case 7:
169
+ raw = _f.sent();
170
+ expect(raw[0].title_enc_srt).toBe('ban');
171
+ expect(raw[0].title).not.toContain('banana');
172
+ _d = 0, ids_1 = ids;
173
+ _f.label = 8;
174
+ case 8:
175
+ if (!(_d < ids_1.length)) return [3 /*break*/, 11];
176
+ id = ids_1[_d];
177
+ return [4 /*yield*/, db.delete(sortedTable, { id: id })];
178
+ case 9:
179
+ _f.sent();
180
+ _f.label = 10;
181
+ case 10:
182
+ _d++;
183
+ return [3 /*break*/, 8];
184
+ case 11: return [2 /*return*/];
185
+ }
186
+ });
187
+ }); });
188
+ test('the live loud rejection: ORDER BY an encrypted column with no sortKey throws at query-build time', function () { return __awaiter(void 0, void 0, void 0, function () {
189
+ var tagQb, tagQb2;
190
+ return __generator(this, function (_a) {
191
+ switch (_a.label) {
192
+ case 0:
193
+ tagQb = new db_1.QueryBuilder(uniqueTable.name).sort([{ field: 'name' }]);
194
+ return [4 /*yield*/, expect(db.query(uniqueTable, tagQb)).rejects.toThrow(db_1.EncryptedColumnQueryError)];
195
+ case 1:
196
+ _a.sent();
197
+ tagQb2 = new db_1.QueryBuilder(uniqueTable.name).sort([{ field: 'name' }]);
198
+ return [4 /*yield*/, expect(db.query(uniqueTable, tagQb2)).rejects.toThrow(/no sortKey declared/)];
199
+ case 2:
200
+ _a.sent();
201
+ return [2 /*return*/];
202
+ }
203
+ });
204
+ }); });
205
+ test('uniqueness on the value rides the fingerprint: duplicate value for the same owner rejected; other owners unaffected', function () { return __awaiter(void 0, void 0, void 0, function () {
206
+ var first, otherOwner;
207
+ return __generator(this, function (_a) {
208
+ switch (_a.label) {
209
+ case 0: return [4 /*yield*/, db.insert(uniqueTable, { scope: OWNER_A, name: 'oncologist' })];
210
+ case 1:
211
+ first = _a.sent();
212
+ return [4 /*yield*/, expect(db.insert(uniqueTable, { scope: OWNER_A, name: 'oncologist' })).rejects.toThrow()];
213
+ case 2:
214
+ _a.sent();
215
+ return [4 /*yield*/, db.insert(uniqueTable, { scope: OWNER_B, name: 'oncologist' })];
216
+ case 3:
217
+ otherOwner = _a.sent();
218
+ return [4 /*yield*/, db.delete(uniqueTable, { id: first.id })];
219
+ case 4:
220
+ _a.sent();
221
+ return [4 /*yield*/, db.delete(uniqueTable, { id: otherOwner.id })];
222
+ case 5:
223
+ _a.sent();
224
+ return [2 /*return*/];
225
+ }
226
+ });
227
+ }); });
228
+ });
229
+ //# sourceMappingURL=EncryptionSortAndUnique.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EncryptionSortAndUnique.test.js","sourceRoot":"","sources":["../../test/EncryptionSortAndUnique.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './util/getDropTestTable';
2
2
  export * from './util/SpannerEmulatorProvisioner';
3
3
  export * from './util/serviceUpdateVerbsTestTables';
4
+ export * from './util/columnEncryptionTestTables';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../test/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../test/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC"}
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./util/getDropTestTable"), exports);
18
18
  __exportStar(require("./util/SpannerEmulatorProvisioner"), exports);
19
19
  __exportStar(require("./util/serviceUpdateVerbsTestTables"), exports);
20
+ __exportStar(require("./util/columnEncryptionTestTables"), exports);
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../test/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,oEAAkD;AAClD,sEAAoD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../test/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,oEAAkD;AAClD,sEAAoD;AACpD,oEAAkD"}
@@ -0,0 +1,23 @@
1
+ import { Table, TableManager } from '@proteinjs/db';
2
+ import { SpannerDriver } from '@proteinjs/db-driver-spanner';
3
+ /**
4
+ * Schema loading for the column-encryption suites. `Db.delete` consults the reverse-cascade
5
+ * edge index over the WHOLE static table registry, and dynamic-reference edges are
6
+ * target-agnostic — so a delete from ANY table queries every registered table holding a
7
+ * `reverseCascadeDelete` dynamic-reference column (the cascade-delete test tables). A
8
+ * single-file run must therefore create those alongside the suite's own tables, plus the
9
+ * framework's data-key table. Serial `loadTable` (never batch `loadTables`): the registry
10
+ * deliberately holds same-name table pairs for schema-change tests, which a batch create
11
+ * would collide on.
12
+ *
13
+ * @internal This module is intended to be used only in tests.
14
+ */
15
+ export declare const loadColumnEncryptionTestSchema: (tableManager: TableManager, suiteTables: Table<any>[]) => Promise<void>;
16
+ /**
17
+ * Clean-slate purge of a suite's tables (rows + their derived token tables) in beforeAll:
18
+ * a prior run killed mid-flight (or a teardown starved out by shared-emulator contention)
19
+ * leaves seeded rows behind, and exact-match search assertions must never depend on a
20
+ * previous process having exited cleanly.
21
+ */
22
+ export declare const purgeColumnEncryptionTestRows: (spannerDriver: SpannerDriver, suiteTables: Table<any>[]) => Promise<void>;
23
+ //# sourceMappingURL=columnEncryptionTestHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columnEncryptionTestHarness.d.ts","sourceRoot":"","sources":["../../../test/util/columnEncryptionTestHarness.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE9F,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,iBAC3B,YAAY,eACb,MAAM,GAAG,CAAC,EAAE,KACxB,QAAQ,IAAI,CASd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,kBACzB,aAAa,eACf,MAAM,GAAG,CAAC,EAAE,KACxB,QAAQ,IAAI,CAcd,CAAC"}