Skip to content

Commit c90007e

Browse files
authored
Merge pull request #255 from cipherstash/chore/use-latest-cipherstash-client
Update to protect-ffi 0.19.0
2 parents cdb2e71 + 622b684 commit c90007e

File tree

6 files changed

+145
-80
lines changed

6 files changed

+145
-80
lines changed

.changeset/tough-aliens-type.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cipherstash/protect": patch
3+
---
4+
5+
Update @cipherstash/protect-ffi to 0.19.0
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import 'dotenv/config'
2+
import { csColumn, csTable } from '@cipherstash/schema'
3+
import { describe, expect, it, beforeAll } from 'vitest'
4+
import { protect } from '../src'
5+
6+
const users = csTable('users', {
7+
email: csColumn('email'),
8+
})
9+
10+
describe('k-field backward compatibility', () => {
11+
let protectClient: Awaited<ReturnType<typeof protect>>
12+
13+
beforeAll(async () => {
14+
protectClient = await protect({ schemas: [users] })
15+
})
16+
17+
it('should encrypt new data WITHOUT k field (forward compatibility)', async () => {
18+
const testData = 'test@example.com'
19+
20+
const result = await protectClient.encrypt(testData, {
21+
column: users.email,
22+
table: users,
23+
})
24+
25+
if (result.failure) {
26+
throw new Error(`Encryption failed: ${result.failure.message}`)
27+
}
28+
29+
// Forward compatibility: new encryptions should NOT have k field
30+
expect(result.data).not.toHaveProperty('k')
31+
expect(result.data).toHaveProperty('c')
32+
expect(result.data).toHaveProperty('v')
33+
expect(result.data).toHaveProperty('i')
34+
}, 30000)
35+
36+
it('should decrypt data with legacy k field (backward compatibility)', async () => {
37+
// First encrypt some data
38+
const testData = 'legacy@example.com'
39+
40+
const encrypted = await protectClient.encrypt(testData, {
41+
column: users.email,
42+
table: users,
43+
})
44+
45+
if (encrypted.failure) {
46+
throw new Error(`Encryption failed: ${encrypted.failure.message}`)
47+
}
48+
49+
// Simulate legacy payload by adding k field to the encrypted data
50+
const legacyPayload = {
51+
...encrypted.data,
52+
k: 'ct', // Legacy discriminant field - should be ignored during decryption
53+
}
54+
55+
// Decrypt should succeed even with legacy k field present
56+
const result = await protectClient.decrypt(legacyPayload)
57+
58+
if (result.failure) {
59+
throw new Error(`Decryption failed: ${result.failure.message}`)
60+
}
61+
62+
expect(result.data).toBe(testData)
63+
}, 30000)
64+
})

packages/protect/__tests__/json-protect.test.ts

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('JSON encryption and decryption', () => {
5555
}
5656

5757
// Verify encrypted field
58-
expect(ciphertext.data).toHaveProperty('k')
58+
expect(ciphertext.data).not.toHaveProperty('k')
5959

6060
const plaintext = await protectClient.decrypt(ciphertext.data)
6161

@@ -107,7 +107,7 @@ describe('JSON encryption and decryption', () => {
107107
}
108108

109109
// Verify encrypted field
110-
expect(ciphertext.data).toHaveProperty('k')
110+
expect(ciphertext.data).not.toHaveProperty('k')
111111

112112
const plaintext = await protectClient.decrypt(ciphertext.data)
113113

@@ -149,7 +149,7 @@ describe('JSON encryption and decryption', () => {
149149
}
150150

151151
// Verify encrypted field
152-
expect(ciphertext.data).toHaveProperty('k')
152+
expect(ciphertext.data).not.toHaveProperty('k')
153153

154154
const plaintext = await protectClient.decrypt(ciphertext.data)
155155

@@ -176,7 +176,7 @@ describe('JSON encryption and decryption', () => {
176176
}
177177

178178
// Verify encrypted field
179-
expect(ciphertext.data).toHaveProperty('k')
179+
expect(ciphertext.data).not.toHaveProperty('k')
180180

181181
const plaintext = await protectClient.decrypt(ciphertext.data)
182182

@@ -214,9 +214,9 @@ describe('JSON model encryption and decryption', () => {
214214
}
215215

216216
// Verify encrypted fields
217-
expect(encryptedModel.data.email).toHaveProperty('k')
218-
expect(encryptedModel.data.address).toHaveProperty('k')
219-
expect(encryptedModel.data.json).toHaveProperty('k')
217+
expect(encryptedModel.data.email).not.toHaveProperty('k')
218+
expect(encryptedModel.data.address).not.toHaveProperty('k')
219+
expect(encryptedModel.data.json).not.toHaveProperty('k')
220220

221221
// Verify non-encrypted fields remain unchanged
222222
expect(encryptedModel.data.id).toBe('1')
@@ -254,8 +254,8 @@ describe('JSON model encryption and decryption', () => {
254254
}
255255

256256
// Verify encrypted fields
257-
expect(encryptedModel.data.email).toHaveProperty('k')
258-
expect(encryptedModel.data.address).toHaveProperty('k')
257+
expect(encryptedModel.data.email).not.toHaveProperty('k')
258+
expect(encryptedModel.data.address).not.toHaveProperty('k')
259259
expect(encryptedModel.data.json).toBeNull()
260260

261261
const decryptedResult = await protectClient.decryptModel<User>(
@@ -289,8 +289,8 @@ describe('JSON model encryption and decryption', () => {
289289
}
290290

291291
// Verify encrypted fields
292-
expect(encryptedModel.data.email).toHaveProperty('k')
293-
expect(encryptedModel.data.address).toHaveProperty('k')
292+
expect(encryptedModel.data.email).not.toHaveProperty('k')
293+
expect(encryptedModel.data.address).not.toHaveProperty('k')
294294
expect(encryptedModel.data.json).toBeUndefined()
295295

296296
const decryptedResult = await protectClient.decryptModel<User>(
@@ -326,13 +326,13 @@ describe('JSON bulk encryption and decryption', () => {
326326
expect(encryptedData.data).toHaveLength(3)
327327
expect(encryptedData.data[0]).toHaveProperty('id', 'user1')
328328
expect(encryptedData.data[0]).toHaveProperty('data')
329-
expect(encryptedData.data[0].data).toHaveProperty('k')
329+
expect(encryptedData.data[0].data).not.toHaveProperty('k')
330330
expect(encryptedData.data[1]).toHaveProperty('id', 'user2')
331331
expect(encryptedData.data[1]).toHaveProperty('data')
332-
expect(encryptedData.data[1].data).toHaveProperty('k')
332+
expect(encryptedData.data[1].data).not.toHaveProperty('k')
333333
expect(encryptedData.data[2]).toHaveProperty('id', 'user3')
334334
expect(encryptedData.data[2]).toHaveProperty('data')
335-
expect(encryptedData.data[2].data).toHaveProperty('k')
335+
expect(encryptedData.data[2].data).not.toHaveProperty('k')
336336

337337
// Now decrypt the data
338338
const decryptedData = await protectClient.bulkDecrypt(encryptedData.data)
@@ -380,13 +380,13 @@ describe('JSON bulk encryption and decryption', () => {
380380
expect(encryptedData.data).toHaveLength(3)
381381
expect(encryptedData.data[0]).toHaveProperty('id', 'user1')
382382
expect(encryptedData.data[0]).toHaveProperty('data')
383-
expect(encryptedData.data[0].data).toHaveProperty('k')
383+
expect(encryptedData.data[0].data).not.toHaveProperty('k')
384384
expect(encryptedData.data[1]).toHaveProperty('id', 'user2')
385385
expect(encryptedData.data[1]).toHaveProperty('data')
386386
expect(encryptedData.data[1].data).toBeNull()
387387
expect(encryptedData.data[2]).toHaveProperty('id', 'user3')
388388
expect(encryptedData.data[2]).toHaveProperty('data')
389-
expect(encryptedData.data[2].data).toHaveProperty('k')
389+
expect(encryptedData.data[2].data).not.toHaveProperty('k')
390390

391391
// Now decrypt the data
392392
const decryptedData = await protectClient.bulkDecrypt(encryptedData.data)
@@ -447,12 +447,12 @@ describe('JSON bulk encryption and decryption', () => {
447447
}
448448

449449
// Verify encrypted fields for each model
450-
expect(encryptedModels.data[0].email).toHaveProperty('k')
451-
expect(encryptedModels.data[0].address).toHaveProperty('k')
452-
expect(encryptedModels.data[0].json).toHaveProperty('k')
453-
expect(encryptedModels.data[1].email).toHaveProperty('k')
454-
expect(encryptedModels.data[1].address).toHaveProperty('k')
455-
expect(encryptedModels.data[1].json).toHaveProperty('k')
450+
expect(encryptedModels.data[0].email).not.toHaveProperty('k')
451+
expect(encryptedModels.data[0].address).not.toHaveProperty('k')
452+
expect(encryptedModels.data[0].json).not.toHaveProperty('k')
453+
expect(encryptedModels.data[1].email).not.toHaveProperty('k')
454+
expect(encryptedModels.data[1].address).not.toHaveProperty('k')
455+
expect(encryptedModels.data[1].json).not.toHaveProperty('k')
456456

457457
// Verify non-encrypted fields remain unchanged
458458
expect(encryptedModels.data[0].id).toBe('1')
@@ -511,7 +511,7 @@ describe('JSON encryption with lock context', () => {
511511
}
512512

513513
// Verify encrypted field
514-
expect(ciphertext.data).toHaveProperty('k')
514+
expect(ciphertext.data).not.toHaveProperty('k')
515515

516516
const plaintext = await protectClient
517517
.decrypt(ciphertext.data)
@@ -557,8 +557,8 @@ describe('JSON encryption with lock context', () => {
557557
}
558558

559559
// Verify encrypted fields
560-
expect(encryptedModel.data.email).toHaveProperty('k')
561-
expect(encryptedModel.data.json).toHaveProperty('k')
560+
expect(encryptedModel.data.email).not.toHaveProperty('k')
561+
expect(encryptedModel.data.json).not.toHaveProperty('k')
562562

563563
const decryptedResult = await protectClient
564564
.decryptModel(encryptedModel.data)
@@ -606,10 +606,10 @@ describe('JSON encryption with lock context', () => {
606606
expect(encryptedData.data).toHaveLength(2)
607607
expect(encryptedData.data[0]).toHaveProperty('id', 'user1')
608608
expect(encryptedData.data[0]).toHaveProperty('data')
609-
expect(encryptedData.data[0].data).toHaveProperty('k')
609+
expect(encryptedData.data[0].data).not.toHaveProperty('k')
610610
expect(encryptedData.data[1]).toHaveProperty('id', 'user2')
611611
expect(encryptedData.data[1]).toHaveProperty('data')
612-
expect(encryptedData.data[1].data).toHaveProperty('k')
612+
expect(encryptedData.data[1].data).not.toHaveProperty('k')
613613

614614
// Decrypt with lock context
615615
const decryptedData = await protectClient
@@ -670,8 +670,8 @@ describe('JSON nested object encryption', () => {
670670
}
671671

672672
// Verify encrypted fields
673-
expect(encryptedModel.data.email).toHaveProperty('k')
674-
expect(encryptedModel.data.metadata?.profile).toHaveProperty('k')
673+
expect(encryptedModel.data.email).not.toHaveProperty('k')
674+
expect(encryptedModel.data.metadata?.profile).not.toHaveProperty('k')
675675
expect(encryptedModel.data.metadata?.settings?.preferences).toHaveProperty(
676676
'c',
677677
)
@@ -714,7 +714,7 @@ describe('JSON nested object encryption', () => {
714714
}
715715

716716
// Verify null fields are preserved
717-
expect(encryptedModel.data.email).toHaveProperty('k')
717+
expect(encryptedModel.data.email).not.toHaveProperty('k')
718718
expect(encryptedModel.data.metadata?.profile).toBeNull()
719719
expect(encryptedModel.data.metadata?.settings?.preferences).toBeNull()
720720

@@ -753,7 +753,7 @@ describe('JSON nested object encryption', () => {
753753
}
754754

755755
// Verify undefined fields are preserved
756-
expect(encryptedModel.data.email).toHaveProperty('k')
756+
expect(encryptedModel.data.email).not.toHaveProperty('k')
757757
expect(encryptedModel.data.metadata?.profile).toBeUndefined()
758758
expect(encryptedModel.data.metadata?.settings?.preferences).toBeUndefined()
759759

@@ -799,7 +799,7 @@ describe('JSON edge cases and error handling', () => {
799799
}
800800

801801
// Verify encrypted field
802-
expect(ciphertext.data).toHaveProperty('k')
802+
expect(ciphertext.data).not.toHaveProperty('k')
803803

804804
const plaintext = await protectClient.decrypt(ciphertext.data)
805805

@@ -847,7 +847,7 @@ describe('JSON edge cases and error handling', () => {
847847
}
848848

849849
// Verify encrypted field
850-
expect(ciphertext.data).toHaveProperty('k')
850+
expect(ciphertext.data).not.toHaveProperty('k')
851851

852852
const plaintext = await protectClient.decrypt(ciphertext.data)
853853

@@ -948,7 +948,7 @@ describe('JSON advanced scenarios', () => {
948948
}
949949

950950
// Verify encrypted field
951-
expect(ciphertext.data).toHaveProperty('k')
951+
expect(ciphertext.data).not.toHaveProperty('k')
952952

953953
const plaintext = await protectClient.decrypt(ciphertext.data)
954954

@@ -975,7 +975,7 @@ describe('JSON advanced scenarios', () => {
975975
}
976976

977977
// Verify encrypted field
978-
expect(ciphertext.data).toHaveProperty('k')
978+
expect(ciphertext.data).not.toHaveProperty('k')
979979

980980
const plaintext = await protectClient.decrypt(ciphertext.data)
981981

@@ -1010,7 +1010,7 @@ describe('JSON advanced scenarios', () => {
10101010
}
10111011

10121012
// Verify encrypted field
1013-
expect(ciphertext.data).toHaveProperty('k')
1013+
expect(ciphertext.data).not.toHaveProperty('k')
10141014

10151015
const plaintext = await protectClient.decrypt(ciphertext.data)
10161016

@@ -1045,7 +1045,7 @@ describe('JSON advanced scenarios', () => {
10451045
}
10461046

10471047
// Verify encrypted field
1048-
expect(ciphertext.data).toHaveProperty('k')
1048+
expect(ciphertext.data).not.toHaveProperty('k')
10491049

10501050
const plaintext = await protectClient.decrypt(ciphertext.data)
10511051

@@ -1081,7 +1081,7 @@ describe('JSON advanced scenarios', () => {
10811081
}
10821082

10831083
// Verify encrypted field
1084-
expect(ciphertext.data).toHaveProperty('k')
1084+
expect(ciphertext.data).not.toHaveProperty('k')
10851085

10861086
const plaintext = await protectClient.decrypt(ciphertext.data)
10871087

@@ -1140,7 +1140,7 @@ describe('JSON error handling and edge cases', () => {
11401140
}
11411141

11421142
// Verify encrypted field
1143-
expect(ciphertext.data).toHaveProperty('k')
1143+
expect(ciphertext.data).not.toHaveProperty('k')
11441144

11451145
const plaintext = await protectClient.decrypt(ciphertext.data)
11461146

@@ -1169,7 +1169,7 @@ describe('JSON error handling and edge cases', () => {
11691169
}
11701170

11711171
// Verify encrypted field
1172-
expect(ciphertext.data).toHaveProperty('k')
1172+
expect(ciphertext.data).not.toHaveProperty('k')
11731173

11741174
const plaintext = await protectClient.decrypt(ciphertext.data)
11751175

@@ -1206,7 +1206,7 @@ describe('JSON error handling and edge cases', () => {
12061206
}
12071207

12081208
// Verify encrypted field
1209-
expect(ciphertext.data).toHaveProperty('k')
1209+
expect(ciphertext.data).not.toHaveProperty('k')
12101210

12111211
const plaintext = await protectClient.decrypt(ciphertext.data)
12121212

packages/protect/__tests__/number-protect.test.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -304,17 +304,13 @@ describe('Bulk encryption and decryption', () => {
304304
expect(encryptedData.data[2]).toHaveProperty('data')
305305
expect(encryptedData.data[2].data).toHaveProperty('c')
306306

307-
expect(encryptedData.data[0].data?.k).toBe('ct')
308-
expect(encryptedData.data[1].data?.k).toBe('ct')
309-
expect(encryptedData.data[2].data?.k).toBe('ct')
307+
// Forward compatibility: new encryptions should NOT have k field
308+
expect(encryptedData.data[0].data).not.toHaveProperty('k')
309+
expect(encryptedData.data[1].data).not.toHaveProperty('k')
310+
expect(encryptedData.data[2].data).not.toHaveProperty('k')
310311

311312
// Verify all encrypted values are different
312-
const getCiphertext = (
313-
data: { k?: string; c?: unknown } | null | undefined,
314-
) => {
315-
if (data?.k === 'ct') return data.c
316-
return data?.c
317-
}
313+
const getCiphertext = (data: { c?: unknown } | null | undefined) => data?.c
318314

319315
expect(getCiphertext(encryptedData.data[0].data)).not.toBe(
320316
getCiphertext(encryptedData.data[1].data),

packages/protect/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
},
6161
"dependencies": {
6262
"@byteslice/result": "^0.2.0",
63-
"@cipherstash/protect-ffi": "0.18.1",
63+
"@cipherstash/protect-ffi": "0.19.0",
6464
"@cipherstash/schema": "workspace:*",
6565
"zod": "^3.24.2"
6666
},

0 commit comments

Comments
 (0)