@reproapp/node-sdk 0.0.3 → 0.0.5

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 (45) hide show
  1. package/README.md +36 -2
  2. package/dist/index.d.ts +140 -15
  3. package/dist/index.js +4927 -927
  4. package/dist/ingest/client.d.ts +10 -0
  5. package/dist/ingest/client.js +158 -0
  6. package/dist/ingest/mapper.d.ts +2 -0
  7. package/dist/ingest/mapper.js +92 -0
  8. package/dist/ingest/types.d.ts +40 -0
  9. package/dist/ingest/types.js +2 -0
  10. package/dist/ingest/worker.js +19 -0
  11. package/dist/integrations/sendgrid.d.ts +2 -4
  12. package/dist/integrations/sendgrid.js +4 -14
  13. package/dist/privacy-fallback.d.ts +1 -0
  14. package/dist/privacy-fallback.js +27 -0
  15. package/dist/privacy-redaction.d.ts +3 -0
  16. package/dist/privacy-redaction.js +38 -0
  17. package/dist/privacy.d.ts +108 -0
  18. package/dist/privacy.js +2868 -0
  19. package/dist/trace-materializer-worker.d.ts +1 -0
  20. package/dist/trace-materializer-worker.js +33 -0
  21. package/docs/tracing.md +1 -0
  22. package/package.json +8 -2
  23. package/src/index.ts +5583 -954
  24. package/src/ingest/client.ts +194 -0
  25. package/src/ingest/mapper.ts +104 -0
  26. package/src/ingest/types.ts +42 -0
  27. package/src/integrations/sendgrid.ts +6 -19
  28. package/src/privacy-fallback.ts +25 -0
  29. package/src/privacy-redaction.ts +37 -0
  30. package/src/privacy.ts +3593 -0
  31. package/src/trace-materializer-worker.ts +39 -0
  32. package/test/circular-capture.test.js +111 -0
  33. package/test/disable-subtree.test.js +154 -0
  34. package/test/integration-unawaited.js +183 -0
  35. package/test/kafka-runtime-privacy-policy.test.js +285 -0
  36. package/test/privacy-runtime-policy.test.js +2043 -0
  37. package/test/promise-map.test.js +72 -0
  38. package/test/unawaited.test.js +163 -0
  39. package/test/wrap-plugin-arrow-args.test.js +80 -0
  40. package/tracer/cjs-hook.js +0 -1
  41. package/tracer/wrap-plugin.js +96 -10
  42. package/dist/redaction.d.ts +0 -44
  43. package/dist/redaction.js +0 -167
  44. package/dist/server.js +0 -26
  45. /package/dist/{server.d.ts → ingest/worker.d.ts} +0 -0
@@ -0,0 +1,2043 @@
1
+ const assert = require('assert');
2
+ const {
3
+ applyRuntimePrivacyPolicy,
4
+ applyRuntimePrivacyPolicyAsync,
5
+ clearRuntimePrivacyProvenance,
6
+ normalizeRuntimePrivacyPolicy,
7
+ } = require('../dist/privacy');
8
+
9
+ function policyFromStatements(statements) {
10
+ return normalizeRuntimePrivacyPolicy({
11
+ environment: 'dev',
12
+ groups: [{ gid: 'test', scope: 'FIELD', selector: 'field:test', statements }],
13
+ });
14
+ }
15
+
16
+ function policyFromStatementsAndRawTextHints(statements, rawTextHints) {
17
+ return normalizeRuntimePrivacyPolicy({
18
+ environment: 'dev',
19
+ rawTextHints,
20
+ groups: [{ gid: 'test', scope: 'FIELD', selector: 'field:test', statements }],
21
+ });
22
+ }
23
+
24
+ async function testSerializedJsonStringsUseNestedRulesAndFallbacks() {
25
+ const policy = policyFromStatements([
26
+ {
27
+ sid: 'drop-webhook-secret',
28
+ when: {
29
+ scope: 'FIELD',
30
+ selector: 'field:webhookSecret',
31
+ target: 'db.query.metadata.webhookSecret|trace.returnValue.metadata.webhookSecret|response.body.data.metadata.webhookSecret',
32
+ },
33
+ apply: { action: 'DROP' },
34
+ meta: { priority: 1 },
35
+ },
36
+ ]);
37
+
38
+ const rawPayload = {
39
+ safeOrderId: 'ORD-123',
40
+ caseId: 'CASE-53FE88B2',
41
+ paymentInstrument: {
42
+ cardLast4: '4242',
43
+ cvv: '123',
44
+ fullPan: '4242 4242 4242 4242',
45
+ },
46
+ metadata: {
47
+ webhookSecret: 'whsec_abcdefghijklmnopqrstuvwxyz',
48
+ providerConnection: 'postgres://drill:secret@payments.internal:5432/security',
49
+ providerToken: 'ghp_abcdefghijklmnopqrstuvwxyz1234567890',
50
+ supportEmail: 'support@example.com',
51
+ },
52
+ headersSnapshot: {
53
+ 'x-api-key': 'rk_live_debugoverride1234567890',
54
+ cookie: 'sid=SessionSecret123; refresh=RefreshOverrideSecret456',
55
+ },
56
+ };
57
+
58
+ const input = {
59
+ command: 'set',
60
+ args: ['datalab:drills:by-case:CASE-53FE88B2', JSON.stringify(rawPayload)],
61
+ };
62
+
63
+ const transformed = await applyRuntimePrivacyPolicyAsync(policy, 'db.query', input, {
64
+ appId: 'APP_test',
65
+ appSecret: 'secret',
66
+ db: { type: 'redis', collection: 'redis', op: 'set' },
67
+ });
68
+ const parsed = JSON.parse(transformed.args[1]);
69
+
70
+ assert.strictEqual(transformed.args[0], 'datalab:drills:by-case:CASE-53FE88B2');
71
+ assert.strictEqual(parsed.safeOrderId, 'ORD-123');
72
+ assert.strictEqual(parsed.caseId, 'CASE-53FE88B2');
73
+ assert.strictEqual(parsed.paymentInstrument.cardLast4, '[dropped]');
74
+ assert.strictEqual(parsed.paymentInstrument.cvv, '[dropped]');
75
+ assert.strictEqual(parsed.paymentInstrument.fullPan, '[dropped]');
76
+ assert.strictEqual(parsed.metadata.webhookSecret, '[dropped]');
77
+ assert.strictEqual(parsed.metadata.providerConnection, '[dropped]');
78
+ assert.strictEqual(parsed.metadata.providerToken, '[dropped]');
79
+ assert.match(parsed.metadata.supportEmail, /^email_tok_[a-f0-9]{12}$/);
80
+ assert.strictEqual(parsed.headersSnapshot['x-api-key'], '[dropped]');
81
+ assert.strictEqual(parsed.headersSnapshot.cookie, '[dropped]');
82
+ }
83
+
84
+ async function testLongSerializedJsonStringsAreTransformedBeforeTruncation() {
85
+ const rawPayload = {
86
+ id: '69ed2d5c585264544573ea4f',
87
+ safeOrderId: 'ORD-123',
88
+ padding: 'x'.repeat(3000),
89
+ nested: {
90
+ cardLast4: '4242',
91
+ cvv: '123',
92
+ apiKey: 'rk_live_debugoverride1234567890',
93
+ customerEmail: 'john@example.com',
94
+ },
95
+ };
96
+ const input = { args: ['cache:key:69ed2d5c585264544573ea4f', JSON.stringify(rawPayload)] };
97
+
98
+ const transformed = await applyRuntimePrivacyPolicyAsync(null, 'db.query', input, {
99
+ appId: 'APP_test',
100
+ appSecret: 'secret',
101
+ db: { type: 'redis', collection: 'redis', op: 'set' },
102
+ });
103
+ const parsed = JSON.parse(transformed.args[1]);
104
+
105
+ assert.strictEqual(parsed.id, '69ed2d5c585264544573ea4f');
106
+ assert.strictEqual(parsed.safeOrderId, 'ORD-123');
107
+ assert.strictEqual(parsed.nested.cardLast4, '[dropped]');
108
+ assert.strictEqual(parsed.nested.cvv, '[dropped]');
109
+ assert.strictEqual(parsed.nested.apiKey, '[dropped]');
110
+ assert.match(parsed.nested.customerEmail, /^email_tok_[a-f0-9]{12}$/);
111
+ }
112
+
113
+ async function testSerializedRedisPayloadTokenizesNestedReviewerIdentity() {
114
+ const rawPayload = {
115
+ id: '69ee0619a8e4553a9905c0c6',
116
+ reference: 'SLB-MOFR1QG7-TBAMUA',
117
+ providerPayload: {
118
+ reviewer: {
119
+ name: 'Mira Sentinel',
120
+ email: 'signal.reviewer@example.com',
121
+ },
122
+ system: {
123
+ component: 'gateway-router',
124
+ environment: 'sandbox',
125
+ },
126
+ },
127
+ snapshot: {
128
+ providerPayload: {
129
+ reviewer: {
130
+ name: 'Mira Sentinel',
131
+ email: 'signal.reviewer@example.com',
132
+ },
133
+ },
134
+ },
135
+ };
136
+ const input = {
137
+ args: ['signallab:drills:by-id:69ee0619a8e4553a9905c0c6', JSON.stringify(rawPayload)],
138
+ };
139
+
140
+ const transformed = await applyRuntimePrivacyPolicyAsync(null, 'db.query', input, {
141
+ appId: 'APP_test',
142
+ appSecret: 'secret',
143
+ db: { type: 'redis', collection: 'redis', op: 'set' },
144
+ });
145
+ const parsed = JSON.parse(transformed.args[1]);
146
+ const serialized = JSON.stringify(parsed);
147
+
148
+ assert(!serialized.includes('Mira Sentinel'), serialized);
149
+ assert(!serialized.includes('signal.reviewer@example.com'), serialized);
150
+ assert.match(parsed.providerPayload.reviewer.name, /^name_tok_[a-f0-9]{12}$/);
151
+ assert.match(parsed.providerPayload.reviewer.email, /^email_tok_[a-f0-9]{12}$/);
152
+ assert.match(parsed.snapshot.providerPayload.reviewer.name, /^name_tok_[a-f0-9]{12}$/);
153
+ assert.match(parsed.snapshot.providerPayload.reviewer.email, /^email_tok_[a-f0-9]{12}$/);
154
+ assert.strictEqual(parsed.providerPayload.system.component, 'gateway-router');
155
+ assert.strictEqual(parsed.providerPayload.system.environment, 'sandbox');
156
+ }
157
+
158
+ async function testSummarizedSerializedJsonKeepsOperationalLeavesReadable() {
159
+ const policy = policyFromStatements([
160
+ {
161
+ sid: 'summarize-serialized-provider-payload',
162
+ when: {
163
+ scope: 'FIELD',
164
+ selector: 'field:serializedProviderPayload',
165
+ target: 'db.query.args[1].serializedProviderPayload',
166
+ },
167
+ apply: { action: 'SUMMARIZE' },
168
+ meta: { priority: 1 },
169
+ },
170
+ ]);
171
+ const serializedProviderPayload = JSON.stringify({
172
+ providerPayload: {
173
+ provider: 'signallab-risk-router-v2',
174
+ status: 'blocked',
175
+ reasonCode: 'secret_rotation_required',
176
+ system: {
177
+ component: 'gateway-router',
178
+ environment: 'sandbox',
179
+ region: 'us-west-2',
180
+ },
181
+ workflow: {
182
+ lane: 'rollback-review-high',
183
+ taskStatus: 'todo',
184
+ },
185
+ reviewer: {
186
+ name: 'Mira Sentinel',
187
+ email: 'signal.reviewer@example.com',
188
+ },
189
+ credentials: {
190
+ webhookSecret: 'whsec_abcdefghijklmnopqrstuvwxyz',
191
+ },
192
+ },
193
+ evidence: [
194
+ {
195
+ step: 'operator-review',
196
+ status: 'queued',
197
+ safeLane: 'rollback-review-high',
198
+ },
199
+ ],
200
+ headersSnapshot: {
201
+ 'x-workflow-stage': 'tenant-signal-review',
202
+ },
203
+ });
204
+ const input = {
205
+ args: [
206
+ 'signallab:drills:activity',
207
+ JSON.stringify({ serializedProviderPayload }),
208
+ ],
209
+ };
210
+
211
+ const transformed = await applyRuntimePrivacyPolicyAsync(policy, 'db.query', input, {
212
+ appId: 'APP_test',
213
+ appSecret: 'secret',
214
+ db: { type: 'redis', collection: 'redis', op: 'lpush' },
215
+ });
216
+ const parsed = JSON.parse(transformed.args[1]);
217
+ const serialized = JSON.parse(parsed.serializedProviderPayload);
218
+
219
+ assert.strictEqual(serialized.providerPayload.provider, 'signallab-risk-router-v2');
220
+ assert.strictEqual(serialized.providerPayload.status, 'blocked');
221
+ assert.strictEqual(serialized.providerPayload.reasonCode, 'secret_rotation_required');
222
+ assert.strictEqual(serialized.providerPayload.system.component, 'gateway-router');
223
+ assert.strictEqual(serialized.providerPayload.system.environment, 'sandbox');
224
+ assert.strictEqual(serialized.providerPayload.system.region, 'us-west-2');
225
+ assert.strictEqual(serialized.providerPayload.workflow.lane, 'rollback-review-high');
226
+ assert.strictEqual(serialized.evidence[0].step, 'operator-review');
227
+ assert.strictEqual(serialized.evidence[0].safeLane, 'rollback-review-high');
228
+ assert.strictEqual(serialized.headersSnapshot['x-workflow-stage'], 'tenant-signal-review');
229
+ assert.match(serialized.providerPayload.reviewer.name, /^name_tok_[a-f0-9]{12}$/);
230
+ assert.match(serialized.providerPayload.reviewer.email, /^email_tok_[a-f0-9]{12}$/);
231
+ assert.strictEqual(serialized.providerPayload.credentials.webhookSecret, '[dropped]');
232
+ }
233
+
234
+ async function testEmptyArrayBracketTargetsMatchArrayItems() {
235
+ const policy = policyFromStatements([
236
+ {
237
+ sid: 'summarize-description',
238
+ when: {
239
+ scope: 'FIELD',
240
+ selector: 'field:description',
241
+ target: 'response.body.data[].payload.description',
242
+ },
243
+ apply: { action: 'SUMMARIZE' },
244
+ meta: { priority: 1 },
245
+ },
246
+ {
247
+ sid: 'known-signal-description',
248
+ when: {
249
+ scope: 'PATTERN',
250
+ selector: 'signal-lab-description-template',
251
+ target: 'response.body.data[].payload.description',
252
+ pattern: '^SignalLab incident\\s',
253
+ },
254
+ apply: {
255
+ action: 'KEEP_EXACT',
256
+ textPolicy: {
257
+ mode: 'KNOWN_TEMPLATE',
258
+ fragments: [
259
+ { kind: 'literal', text: 'SignalLab incident ' },
260
+ { kind: 'slot', label: 'safeSignalId', action: 'KEEP_EXACT' },
261
+ { kind: 'literal', text: ': feature-flag rollback is queued for verification.' },
262
+ ],
263
+ },
264
+ },
265
+ meta: { priority: 2 },
266
+ },
267
+ ]);
268
+
269
+ const transformed = await applyRuntimePrivacyPolicyAsync(
270
+ policy,
271
+ 'response.body',
272
+ {
273
+ data: [
274
+ {
275
+ payload: {
276
+ description: 'SignalLab incident SIG-FLHIRS2N: feature-flag rollback is queued for verification.',
277
+ },
278
+ },
279
+ ],
280
+ },
281
+ { appId: 'APP_test', routeKey: 'GET /api/integrations/payment-events' },
282
+ );
283
+
284
+ assert.strictEqual(
285
+ transformed.data[0].payload.description,
286
+ 'SignalLab incident SIG-FLHIRS2N: feature-flag rollback is queued for verification.',
287
+ );
288
+ }
289
+
290
+ async function testKnownEvidenceMessagesApplyInsideWrappersAndSerializedPayloads() {
291
+ const evidenceMessageTargets = [
292
+ 'response.body.data[].payload.evidence[].message',
293
+ 'response.body.data[].payload.serializedProviderPayload.evidence[].message',
294
+ 'db.query.doc.payload.evidence[].message',
295
+ 'db.query.doc.payload.serializedProviderPayload.evidence[].message',
296
+ 'trace.returnValue[].payload.evidence[].message',
297
+ 'trace.returnValue[].payload.serializedProviderPayload.evidence[].message',
298
+ ].join('|');
299
+ const policy = policyFromStatements([
300
+ {
301
+ sid: 'summarize-evidence-message',
302
+ when: {
303
+ scope: 'FIELD',
304
+ selector: 'field:message',
305
+ target: evidenceMessageTargets,
306
+ },
307
+ apply: { action: 'SUMMARIZE' },
308
+ meta: { priority: 1 },
309
+ },
310
+ {
311
+ sid: 'known-webhook-evidence-message',
312
+ when: {
313
+ scope: 'PATTERN',
314
+ selector: 'signal-lab-evidence-webhook-message-template',
315
+ target: evidenceMessageTargets,
316
+ pattern: '^Webhook for\\s',
317
+ },
318
+ apply: {
319
+ action: 'KEEP_EXACT',
320
+ textPolicy: {
321
+ mode: 'KNOWN_TEMPLATE',
322
+ fragments: [
323
+ { kind: 'literal', text: 'Webhook for ' },
324
+ { kind: 'slot', label: 'email', action: 'TOKENIZE' },
325
+ { kind: 'literal', text: ' failed on ' },
326
+ { kind: 'slot', label: 'safeSignalId', action: 'KEEP_EXACT' },
327
+ { kind: 'literal', text: '; provider returned token ' },
328
+ { kind: 'slot', label: 'providerToken', action: 'DROP' },
329
+ { kind: 'literal', text: '.' },
330
+ ],
331
+ },
332
+ },
333
+ meta: { priority: 2 },
334
+ },
335
+ {
336
+ sid: 'known-operator-evidence-message',
337
+ when: {
338
+ scope: 'PATTERN',
339
+ selector: 'signal-lab-evidence-operator-message-template',
340
+ target: evidenceMessageTargets,
341
+ pattern: '^Keep task\\s"',
342
+ },
343
+ apply: {
344
+ action: 'KEEP_EXACT',
345
+ textPolicy: {
346
+ mode: 'KNOWN_TEMPLATE',
347
+ fragments: [
348
+ { kind: 'literal', text: 'Keep task "' },
349
+ { kind: 'slot', label: 'taskTitle', action: 'KEEP_EXACT' },
350
+ { kind: 'literal', text: '" in review lane until signal clears for ' },
351
+ { kind: 'slot', label: 'safeSignalId', action: 'KEEP_EXACT' },
352
+ { kind: 'literal', text: '.' },
353
+ ],
354
+ },
355
+ },
356
+ meta: { priority: 3 },
357
+ },
358
+ {
359
+ sid: 'known-serialized-evidence-message',
360
+ when: {
361
+ scope: 'PATTERN',
362
+ selector: 'signal-lab-evidence-serialized-message-template',
363
+ target: evidenceMessageTargets,
364
+ pattern: '^\\{"safeSignalId"',
365
+ },
366
+ apply: {
367
+ action: 'KEEP_EXACT',
368
+ textPolicy: {
369
+ mode: 'KNOWN_TEMPLATE',
370
+ fragments: [
371
+ { kind: 'literal', text: '{"safeSignalId":"' },
372
+ { kind: 'slot', label: 'safeSignalId', action: 'KEEP_EXACT' },
373
+ { kind: 'literal', text: '","email":"' },
374
+ { kind: 'slot', label: 'email', action: 'TOKENIZE' },
375
+ { kind: 'literal', text: '","token":"' },
376
+ { kind: 'slot', label: 'providerToken', action: 'DROP' },
377
+ { kind: 'literal', text: '","card":"' },
378
+ { kind: 'slot', label: 'card', action: 'DROP' },
379
+ { kind: 'literal', text: '","connection":"' },
380
+ { kind: 'slot', label: 'connection', action: 'DROP' },
381
+ { kind: 'literal', text: '"}' },
382
+ ],
383
+ },
384
+ },
385
+ meta: { priority: 4 },
386
+ },
387
+ ]);
388
+
389
+ const evidence = [
390
+ {
391
+ message: 'Webhook for john@example.com failed on SIG-FLHIRS2N; provider returned token sk_live_signallab1234567890abcdef.',
392
+ },
393
+ {
394
+ message: 'Keep task "SignalLab Drill 16:07:13 for john@example.com" in review lane until signal clears for SIG-FLHIRS2N.',
395
+ },
396
+ {
397
+ message: JSON.stringify({
398
+ safeSignalId: 'SIG-FLHIRS2N',
399
+ email: 'john@example.com',
400
+ token: 'ghp_abcdefghijklmnopqrstuvwxyz1234567890',
401
+ card: '4242 4242 4242 4242',
402
+ connection: 'redis://:secret@signal-lab.internal:6379/0',
403
+ }),
404
+ },
405
+ ];
406
+ const input = {
407
+ data: [
408
+ {
409
+ payload: {
410
+ evidence,
411
+ serializedProviderPayload: JSON.stringify({ evidence }),
412
+ },
413
+ },
414
+ ],
415
+ };
416
+
417
+ const transformed = await applyRuntimePrivacyPolicyAsync(
418
+ policy,
419
+ 'response.body',
420
+ input,
421
+ { appId: 'APP_test', routeKey: 'GET /api/integrations/payment-events' },
422
+ );
423
+ const messages = transformed.data[0].payload.evidence.map((item) => item.message);
424
+ const serialized = JSON.parse(transformed.data[0].payload.serializedProviderPayload);
425
+ const serializedMessages = serialized.evidence.map((item) => item.message);
426
+
427
+ for (const message of [...messages, ...serializedMessages]) {
428
+ assert(!message.includes('john@example.com'), message);
429
+ assert(!message.includes('sk_live_signallab1234567890abcdef'), message);
430
+ assert(!message.includes('ghp_abcdefghijklmnopqrstuvwxyz1234567890'), message);
431
+ assert(!message.includes('4242 4242 4242 4242'), message);
432
+ assert(!message.includes('redis://:secret@signal-lab.internal:6379/0'), message);
433
+ assert(!message.includes('Web..ok'), message);
434
+ assert(!message.includes('Sig..Lab'), message);
435
+ }
436
+
437
+ assert.match(messages[0], /^Webhook for email_tok_[a-f0-9]{12} failed on SIG-FLHIRS2N; provider returned token \[dropped\]\.$/);
438
+ assert.match(
439
+ messages[1],
440
+ /^Keep task "SignalLab Drill 16:07:13 for email_tok_[a-f0-9]{12}" in review lane until signal clears for SIG-FLHIRS2N\.$/,
441
+ );
442
+ assert.match(
443
+ messages[2],
444
+ /^\{"safeSignalId":"SIG-FLHIRS2N","email":"email_tok_[a-f0-9]{12}","token":"\[dropped\]","card":"\[dropped\]","connection":"\[dropped\]"\}$/,
445
+ );
446
+ assert.deepStrictEqual(serializedMessages, messages);
447
+ }
448
+
449
+ async function testSerializedJsonIsNotDroppedAsAtomicSecretText() {
450
+ const policy = policyFromStatements([
451
+ {
452
+ sid: 'secret-pattern',
453
+ when: {
454
+ scope: 'PATTERN',
455
+ selector: 'baseline-secrets',
456
+ target: 'response.body',
457
+ pattern: 'whsec_[A-Za-z0-9_]+',
458
+ },
459
+ apply: { action: 'DROP' },
460
+ meta: { priority: 1 },
461
+ },
462
+ ]);
463
+ const serializedProviderPayload = JSON.stringify({
464
+ providerPayload: {
465
+ provider: 'signallab-risk-router-v2',
466
+ system: {
467
+ component: 'gateway-router',
468
+ },
469
+ reviewer: {
470
+ name: 'Mira Sentinel',
471
+ email: 'signal.reviewer@example.com',
472
+ },
473
+ credentials: {
474
+ webhookSecret: 'whsec_abcdefghijklmnopqrstuvwxyz',
475
+ },
476
+ },
477
+ });
478
+
479
+ const transformed = await applyRuntimePrivacyPolicyAsync(
480
+ policy,
481
+ 'response.body',
482
+ { data: { serializedProviderPayload } },
483
+ { appId: 'APP_test' },
484
+ );
485
+ const parsed = JSON.parse(transformed.data.serializedProviderPayload);
486
+
487
+ assert.strictEqual(parsed.providerPayload.provider, 'signallab-risk-router-v2');
488
+ assert.strictEqual(parsed.providerPayload.system.component, 'gateway-router');
489
+ assert.match(parsed.providerPayload.reviewer.name, /^name_tok_[a-f0-9]{12}$/);
490
+ assert.match(parsed.providerPayload.reviewer.email, /^email_tok_[a-f0-9]{12}$/);
491
+ assert.strictEqual(parsed.providerPayload.credentials.webhookSecret, '[dropped]');
492
+ }
493
+
494
+ function testOperationalIdsDoNotFallbackMaskOrLookLikeCreditCards() {
495
+ const policy = policyFromStatements([
496
+ {
497
+ sid: 'summarize-cache-key',
498
+ when: {
499
+ scope: 'FUNCTION',
500
+ selector: 'fn:getCaseCacheKey',
501
+ target: 'trace.returnValue',
502
+ },
503
+ apply: { action: 'SUMMARIZE' },
504
+ meta: { priority: 1 },
505
+ },
506
+ ]);
507
+
508
+ const cacheKey = applyRuntimePrivacyPolicy(
509
+ policy,
510
+ 'trace.returnValue',
511
+ 'datalab:drills:by-case:CASE-53FE88B2',
512
+ { trace: { fn: 'getCaseCacheKey' }, appId: 'APP_test' },
513
+ );
514
+ assert.strictEqual(cacheKey, 'datalab:drills:by-case:CASE-53FE88B2');
515
+
516
+ const headers = applyRuntimePrivacyPolicy(null, 'request.headers', {
517
+ 'x-bug-request-start': '1777148070302',
518
+ 'x-repro-request-rid': '1777148070302-2d2r7',
519
+ 'x-repro-trace-id': '1777148070302-2d2r7',
520
+ 'x-safe-order-id': 'ORD-123',
521
+ }, { appId: 'APP_test' });
522
+
523
+ assert.strictEqual(headers['x-bug-request-start'], '1777148070302');
524
+ assert.strictEqual(headers['x-repro-request-rid'], '1777148070302-2d2r7');
525
+ assert.strictEqual(headers['x-repro-trace-id'], '1777148070302-2d2r7');
526
+ assert.strictEqual(headers['x-safe-order-id'], 'ORD-123');
527
+ }
528
+
529
+ function testPlainObjectsWithIdAreNotCollapsedToObjectId() {
530
+ const input = {
531
+ success: true,
532
+ data: {
533
+ id: '69ed2d5c585264544573ea4f',
534
+ amount: 867.53,
535
+ status: 'failed',
536
+ customerEmail: 'john@example.com',
537
+ cardLast4: '4242',
538
+ },
539
+ };
540
+
541
+ const transformed = applyRuntimePrivacyPolicy(null, 'response.body', input, { appId: 'APP_test' });
542
+
543
+ assert.strictEqual(transformed.success, true);
544
+ assert.strictEqual(transformed.data.id, '69ed2d5c585264544573ea4f');
545
+ assert.strictEqual(transformed.data.amount, 867.53);
546
+ assert.strictEqual(transformed.data.status, 'failed');
547
+ assert.match(transformed.data.customerEmail, /^email_tok_[a-f0-9]{12}$/);
548
+ assert.strictEqual(transformed.data.cardLast4, '[dropped]');
549
+ }
550
+
551
+ function testNestedIdentityFieldsUseGenericSemanticFallback() {
552
+ const input = {
553
+ providerPayload: {
554
+ customer: {
555
+ id: 'cust_external_123',
556
+ name: 'Example Customer',
557
+ email: 'customer@example.com',
558
+ accountId: 'acct_external_456',
559
+ },
560
+ incidentOwner: {
561
+ name: 'Example Owner',
562
+ email: 'owner@example.com',
563
+ },
564
+ routing: {
565
+ taskId: '69ed2d5c585264544573ea4f',
566
+ status: 'declined',
567
+ queue: 'risk-review-high',
568
+ },
569
+ },
570
+ accountId: 'acct_top_level_789',
571
+ safeOrderId: 'ORD-123',
572
+ status: 'failed',
573
+ };
574
+
575
+ const transformed = applyRuntimePrivacyPolicy(null, 'response.body', input, { appId: 'APP_test' });
576
+
577
+ assert.match(transformed.providerPayload.customer.id, /^id_tok_[a-f0-9]{12}$/);
578
+ assert.match(transformed.providerPayload.customer.name, /^name_tok_[a-f0-9]{12}$/);
579
+ assert.match(transformed.providerPayload.customer.email, /^email_tok_[a-f0-9]{12}$/);
580
+ assert.match(transformed.providerPayload.customer.accountId, /^accountId_tok_[a-f0-9]{12}$/);
581
+ assert.match(transformed.providerPayload.incidentOwner.name, /^name_tok_[a-f0-9]{12}$/);
582
+ assert.match(transformed.providerPayload.incidentOwner.email, /^email_tok_[a-f0-9]{12}$/);
583
+ assert.match(transformed.accountId, /^accountId_tok_[a-f0-9]{12}$/);
584
+ assert.strictEqual(transformed.providerPayload.routing.taskId, '69ed2d5c585264544573ea4f');
585
+ assert.strictEqual(transformed.providerPayload.routing.status, 'declined');
586
+ assert.strictEqual(transformed.providerPayload.routing.queue, 'risk-review-high');
587
+ assert.strictEqual(transformed.safeOrderId, 'ORD-123');
588
+ assert.strictEqual(transformed.status, 'failed');
589
+ }
590
+
591
+ function testObjectTokenizePreservesStructure() {
592
+ const policy = policyFromStatements([
593
+ {
594
+ sid: 'bad-container-tokenize',
595
+ when: {
596
+ scope: 'FUNCTION',
597
+ selector: 'fn:badContainerRule',
598
+ target: 'trace.args[0]',
599
+ },
600
+ apply: { action: 'TOKENIZE' },
601
+ meta: { priority: 1 },
602
+ },
603
+ ]);
604
+
605
+ const input = [{
606
+ status: 'failed',
607
+ customer: {
608
+ name: 'Data Lab Customer',
609
+ accountId: 'acct_datalab_1024',
610
+ },
611
+ safeOrderId: 'ORD-123',
612
+ }];
613
+
614
+ const transformed = applyRuntimePrivacyPolicy(policy, 'trace.args', input, {
615
+ appId: 'APP_test',
616
+ trace: { fn: 'badContainerRule' },
617
+ });
618
+
619
+ assert(Array.isArray(transformed));
620
+ assert.strictEqual(typeof transformed[0], 'object');
621
+ assert(!Object.prototype.hasOwnProperty.call(transformed[0], 'token'));
622
+ assert.match(transformed[0].status, /^status_tok_[a-f0-9]{12}$/);
623
+ assert.match(transformed[0].customer.name, /^name_tok_[a-f0-9]{12}$/);
624
+ assert.match(transformed[0].customer.accountId, /^accountId_tok_[a-f0-9]{12}$/);
625
+ assert.match(transformed[0].safeOrderId, /^safeOrderId_tok_[a-f0-9]{12}$/);
626
+ }
627
+
628
+ async function testTopLevelKnownTextPolicyIsAcceptedInSerializedValues() {
629
+ const policy = policyFromStatements([
630
+ {
631
+ sid: 'known-status-note',
632
+ when: {
633
+ scope: 'FIELD',
634
+ selector: 'field:statusNote',
635
+ target: 'db.after.statusNote|db.resultMeta.result.statusNote',
636
+ },
637
+ apply: { action: 'KEEP_EXACT' },
638
+ textPolicy: {
639
+ mode: 'KNOWN_TEMPLATE',
640
+ fragments: [
641
+ { kind: 'literal', text: 'Manual review owner' },
642
+ { kind: 'slot', label: 'incidentOwnerName', action: 'TOKENIZE' },
643
+ { kind: 'literal', text: 'can debug' },
644
+ { kind: 'slot', label: 'safeOrderId', action: 'KEEP_EXACT' },
645
+ { kind: 'literal', text: ', but provider token' },
646
+ { kind: 'slot', label: 'providerToken', action: 'DROP' },
647
+ { kind: 'literal', text: 'must never be logged raw.' },
648
+ ],
649
+ },
650
+ meta: { priority: 1 },
651
+ },
652
+ ]);
653
+ const input = {
654
+ args: [
655
+ 'datalab:drills:by-case:CASE-53FE88B2',
656
+ JSON.stringify({
657
+ statusNote: 'Manual review owner Jane Security can debug ORD-123, but provider token ghp_abcdefghijklmnopqrstuvwxyz1234567890 must never be logged raw.',
658
+ }),
659
+ ],
660
+ };
661
+
662
+ const transformed = await applyRuntimePrivacyPolicyAsync(policy, 'db.query', input, {
663
+ appId: 'APP_test',
664
+ appSecret: 'secret',
665
+ db: { type: 'redis', collection: 'redis', op: 'set' },
666
+ });
667
+ const parsed = JSON.parse(transformed.args[1]);
668
+
669
+ assert(!parsed.statusNote.includes('Jane Security'), parsed.statusNote);
670
+ assert(!parsed.statusNote.includes('ghp_abcdefghijklmnopqrstuvwxyz1234567890'), parsed.statusNote);
671
+ assert.match(
672
+ parsed.statusNote,
673
+ /^Manual review owner incidentOwnerName_tok_[a-f0-9]{12} can debug ORD-123, but provider token \[dropped\] must never be logged raw\.$/,
674
+ );
675
+ }
676
+
677
+ function testUnknownFreeTextLeafStaysExactWithoutExplicitRawMode() {
678
+ const input = {
679
+ success: true,
680
+ data: {
681
+ status: 'failed',
682
+ safeOrderId: 'ORD-123',
683
+ statusNote: 'Manual review owner Jane Security can debug ORD-123, but provider token ghp_abcdefghijklmnopqrstuvwxyz1234567890 must never be logged raw.',
684
+ },
685
+ };
686
+
687
+ const transformed = applyRuntimePrivacyPolicy(null, 'response.body', input, { appId: 'APP_test' });
688
+
689
+ assert.strictEqual(transformed.success, true);
690
+ assert.strictEqual(transformed.data.status, 'failed');
691
+ assert.strictEqual(transformed.data.safeOrderId, 'ORD-123');
692
+ assert.strictEqual(
693
+ transformed.data.statusNote,
694
+ input.data.statusNote,
695
+ );
696
+ }
697
+
698
+ function testRawTextRegexHintsPreserveUnmatchedTextWhenExplicitlyEnabled() {
699
+ const policy = policyFromStatementsAndRawTextHints([
700
+ {
701
+ sid: 'raw-provider-message',
702
+ when: {
703
+ scope: 'FIELD',
704
+ selector: 'message',
705
+ target: 'response.body.data.message',
706
+ },
707
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
708
+ meta: { priority: 1 },
709
+ },
710
+ ], [
711
+ {
712
+ name: 'Internal username',
713
+ scope: 'RAW_TEXT_ONLY',
714
+ action: 'TOKENIZE',
715
+ regex: '\\busr_[a-z0-9]{8}\\b',
716
+ tokenLabel: 'internalUsername',
717
+ },
718
+ ]);
719
+
720
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
721
+ data: {
722
+ message: 'Provider rejected usr_ab12cd34 for john@example.com using token ghp_abcdefghijklmnopqrstuvwxyz1234567890 for order ORD-123',
723
+ },
724
+ }, { appId: 'APP_test' });
725
+
726
+ assert.match(
727
+ transformed.data.message,
728
+ /^Provider rejected internalUsername_tok_[a-f0-9]{12} for email_tok_[a-f0-9]{12} using token ghp_abcdefghijklmnopqrstuvwxyz1234567890 for order ORD-123$/,
729
+ );
730
+ assert(!transformed.data.message.includes('usr_ab12cd34'), transformed.data.message);
731
+ assert(!transformed.data.message.includes('john@example.com'), transformed.data.message);
732
+ assert(!transformed.data.message.includes('Pro..er'), transformed.data.message);
733
+ }
734
+
735
+ function testRawTextRegexHintsSupportMultipleActionsOnSameRawString() {
736
+ const policy = policyFromStatementsAndRawTextHints([
737
+ {
738
+ sid: 'raw-provider-message',
739
+ when: {
740
+ scope: 'FIELD',
741
+ selector: 'message',
742
+ target: 'response.body.data.message',
743
+ },
744
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
745
+ meta: { priority: 1 },
746
+ },
747
+ ], [
748
+ {
749
+ name: 'Opaque diagnostic',
750
+ scope: 'RAW_TEXT_ONLY',
751
+ action: 'TOKENIZE',
752
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
753
+ tokenLabel: 'opaqueDiagnostic',
754
+ },
755
+ {
756
+ name: 'Provider secret',
757
+ scope: 'RAW_TEXT_ONLY',
758
+ action: 'DROP',
759
+ regex: '\\bsk_live_[A-Za-z0-9_-]{8,128}\\b',
760
+ tokenLabel: 'providerSecret',
761
+ },
762
+ ]);
763
+
764
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
765
+ data: {
766
+ message: 'Provider returned opaque ZXQABCDEF123456A19KLM with token sk_live_privacy_abcdef12345678 for order ORD-123',
767
+ },
768
+ }, { appId: 'APP_test' });
769
+
770
+ assert.match(
771
+ transformed.data.message,
772
+ /^Provider returned opaque opaqueDiagnostic_tok_[a-f0-9]{12} with token \[dropped\] for order ORD-123$/,
773
+ );
774
+ assert(!transformed.data.message.includes('ZXQABCDEF123456A19KLM'), transformed.data.message);
775
+ assert(!transformed.data.message.includes('sk_live_privacy_abcdef12345678'), transformed.data.message);
776
+ assert(!transformed.data.message.includes('Pro..er'), transformed.data.message);
777
+ }
778
+
779
+ function testRegexAssistedRawTextRuleBeatsSamePathSafePartialMask() {
780
+ const policy = policyFromStatementsAndRawTextHints([
781
+ {
782
+ sid: 'copied-raw-narrative-safe',
783
+ when: {
784
+ scope: 'FIELD',
785
+ selector: 'rawNarrative',
786
+ target: 'response.body.data.rawNarrative',
787
+ },
788
+ apply: { action: 'SUMMARIZE', rawTextMode: 'SAFE_PARTIAL_MASK' },
789
+ meta: { priority: 1 },
790
+ },
791
+ {
792
+ sid: 'reviewed-raw-narrative-regex',
793
+ when: {
794
+ scope: 'FIELD',
795
+ selector: 'rawNarrative',
796
+ target: 'response.body.data.rawNarrative',
797
+ },
798
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
799
+ meta: { priority: 2 },
800
+ },
801
+ ], [
802
+ {
803
+ name: 'Opaque diagnostic detector',
804
+ scope: 'RAW_TEXT_ONLY',
805
+ action: 'TOKENIZE',
806
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
807
+ tokenLabel: 'opaqueDiagnostic',
808
+ },
809
+ ]);
810
+
811
+ const rawNarrative = 'Provider narrative contains token A1b2C3d4E5f6G7h8J9k0L1m2 and opaque ZXQABCDEF123456A19KLM for debugging.';
812
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
813
+ data: { rawNarrative },
814
+ }, { appId: 'APP_test' });
815
+
816
+ assert.match(
817
+ transformed.data.rawNarrative,
818
+ /^Provider narrative contains token A1b2C3d4E5f6G7h8J9k0L1m2 and opaque opaqueDiagnostic_tok_[a-f0-9]{12} for debugging\.$/,
819
+ );
820
+ assert(!transformed.data.rawNarrative.includes('ZXQABCDEF123456A19KLM'), transformed.data.rawNarrative);
821
+ assert(!transformed.data.rawNarrative.includes('Pro..er'), transformed.data.rawNarrative);
822
+ }
823
+
824
+ function testSyncSafePartialRawTextRunsBuiltInDetectorsBeforeMasking() {
825
+ const policy = policyFromStatements([
826
+ {
827
+ sid: 'raw-narrative-safe',
828
+ when: {
829
+ scope: 'FIELD',
830
+ selector: 'rawNarrative',
831
+ target: 'response.body.data.rawNarrative',
832
+ },
833
+ apply: { action: 'SUMMARIZE', rawTextMode: 'SAFE_PARTIAL_MASK' },
834
+ meta: { priority: 1 },
835
+ },
836
+ ]);
837
+
838
+ const rawNarrative = 'Provider narrative includes authorization Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA== and connection postgres://user:pass@localhost:5432/app.';
839
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
840
+ data: { rawNarrative },
841
+ }, { appId: 'APP_test' });
842
+
843
+ assert(transformed.data.rawNarrative.includes('[auth-token]'), transformed.data.rawNarrative);
844
+ assert(transformed.data.rawNarrative.includes('[connection-string]'), transformed.data.rawNarrative);
845
+ assert(!transformed.data.rawNarrative.includes('Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA=='), transformed.data.rawNarrative);
846
+ assert(!transformed.data.rawNarrative.includes('postgres://user:pass@localhost:5432/app'), transformed.data.rawNarrative);
847
+ }
848
+
849
+ function testRawTextRegexHintsPreferCurrentPathLabel() {
850
+ const policy = policyFromStatementsAndRawTextHints([
851
+ {
852
+ sid: 'opaque-diagnostic',
853
+ when: {
854
+ scope: 'FIELD',
855
+ selector: 'opaqueDiagnostic',
856
+ target: 'response.body.data.metadata.opaqueDiagnostic',
857
+ },
858
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
859
+ meta: { priority: 1 },
860
+ },
861
+ {
862
+ sid: 'opaque-trace-id',
863
+ when: {
864
+ scope: 'FIELD',
865
+ selector: 'opaqueTraceId',
866
+ target: 'response.body.data.opaqueTraceId',
867
+ },
868
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
869
+ meta: { priority: 2 },
870
+ },
871
+ ], [
872
+ {
873
+ name: 'Opaque diagnostic',
874
+ scope: 'RAW_TEXT_ONLY',
875
+ action: 'TOKENIZE',
876
+ regex: '\\bZXQ[A-Z0-9-]{8,80}\\b',
877
+ tokenLabel: 'opaqueDiagnostic',
878
+ },
879
+ {
880
+ name: 'Opaque trace id',
881
+ scope: 'RAW_TEXT_ONLY',
882
+ action: 'TOKENIZE',
883
+ regex: '\\bZXQ[A-Z0-9-]{8,80}\\b',
884
+ tokenLabel: 'opaqueTraceId',
885
+ },
886
+ ]);
887
+
888
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
889
+ data: {
890
+ metadata: {
891
+ opaqueDiagnostic: 'ZXQ9ABCD9911KLM',
892
+ },
893
+ opaqueTraceId: 'ZXQ9ABCD9911KLM-SEC-MOJXXOIH',
894
+ },
895
+ }, { appId: 'APP_test' });
896
+
897
+ assert.match(transformed.data.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
898
+ assert.match(transformed.data.opaqueTraceId, /^opaqueTraceId_tok_[a-f0-9]{12}$/);
899
+ }
900
+
901
+ function testRawTextRegexHintsDoNotRunWithoutExplicitRawTextMode() {
902
+ const policy = policyFromStatementsAndRawTextHints([
903
+ {
904
+ sid: 'default-provider-message',
905
+ when: {
906
+ scope: 'FIELD',
907
+ selector: 'message',
908
+ target: 'response.body.data.message',
909
+ },
910
+ apply: { action: 'SUMMARIZE' },
911
+ meta: { priority: 1 },
912
+ },
913
+ ], [
914
+ {
915
+ name: 'Internal username',
916
+ scope: 'RAW_TEXT_ONLY',
917
+ action: 'TOKENIZE',
918
+ regex: '\\busr_[a-z0-9]{8}\\b',
919
+ tokenLabel: 'internalUsername',
920
+ },
921
+ ]);
922
+
923
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
924
+ data: {
925
+ message: 'Provider rejected usr_ab12cd34 for john@example.com',
926
+ },
927
+ }, { appId: 'APP_test' });
928
+
929
+ assert(!transformed.data.message.includes('internalUsername_tok_'), transformed.data.message);
930
+ assert(!transformed.data.message.includes('john@example.com'), transformed.data.message);
931
+ assert.strictEqual(
932
+ transformed.data.message,
933
+ 'Provider rejected usr_ab12cd34 for email_tok_855f96e983f1',
934
+ );
935
+ }
936
+
937
+ function testRegexAssistedRawTextWithoutHintsKeepsUnmatchedTextExact() {
938
+ const policy = policyFromStatements([
939
+ {
940
+ sid: 'raw-provider-message-without-hints',
941
+ when: {
942
+ scope: 'FIELD',
943
+ selector: 'message',
944
+ target: 'response.body.data.message',
945
+ },
946
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
947
+ meta: { priority: 1 },
948
+ },
949
+ ]);
950
+
951
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
952
+ data: {
953
+ message: 'Provider rejected usr_ab12cd34 for john@example.com',
954
+ },
955
+ }, { appId: 'APP_test' });
956
+
957
+ assert(!transformed.data.message.includes('john@example.com'), transformed.data.message);
958
+ assert.strictEqual(
959
+ transformed.data.message,
960
+ 'Provider rejected usr_ab12cd34 for email_tok_855f96e983f1',
961
+ );
962
+ }
963
+
964
+ function testRawTextRegexHintsDoNotRunOnStructuredFields() {
965
+ const policy = policyFromStatementsAndRawTextHints([
966
+ {
967
+ sid: 'unrelated-message',
968
+ when: {
969
+ scope: 'FIELD',
970
+ selector: 'message',
971
+ target: 'response.body.data.message',
972
+ },
973
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
974
+ meta: { priority: 1 },
975
+ },
976
+ ], [
977
+ {
978
+ name: 'Internal username',
979
+ scope: 'RAW_TEXT_ONLY',
980
+ action: 'TOKENIZE',
981
+ regex: '\\busr_[a-z0-9]{8}\\b',
982
+ tokenLabel: 'internalUsername',
983
+ },
984
+ ]);
985
+
986
+ const transformed = applyRuntimePrivacyPolicy(policy, 'response.body', {
987
+ data: {
988
+ actor: 'usr_ab12cd34',
989
+ },
990
+ }, { appId: 'APP_test' });
991
+
992
+ assert.strictEqual(transformed.data.actor, 'usr_ab12cd34');
993
+ }
994
+
995
+ function testExactSensitiveTargetBeatsExactFunctionKeepExact() {
996
+ const policy = policyFromStatements([
997
+ {
998
+ sid: 'function-keep-positional-owner',
999
+ when: {
1000
+ scope: 'FUNCTION',
1001
+ selector: 'fn:DataDrillsService.buildProviderPayload',
1002
+ target: 'trace.args[4]',
1003
+ },
1004
+ apply: { action: 'KEEP_EXACT' },
1005
+ meta: { priority: 1 },
1006
+ },
1007
+ {
1008
+ sid: 'field-tokenize-positional-owner',
1009
+ when: {
1010
+ scope: 'FIELD',
1011
+ selector: 'field:incidentOwnerName',
1012
+ target: 'trace.args[4]',
1013
+ },
1014
+ apply: { action: 'TOKENIZE' },
1015
+ meta: { priority: 2 },
1016
+ },
1017
+ ]);
1018
+
1019
+ const transformed = applyRuntimePrivacyPolicy(
1020
+ policy,
1021
+ 'trace.args',
1022
+ [{ taskId: '69ed2d5c585264544573ea4f' }, 'ORD-123', 'CASE-123', 'john@example.com', 'Jane Security'],
1023
+ {
1024
+ appId: 'APP_test',
1025
+ trace: { fn: 'DataDrillsService.buildProviderPayload' },
1026
+ },
1027
+ );
1028
+
1029
+ assert.strictEqual(transformed[1], 'ORD-123');
1030
+ assert.strictEqual(transformed[2], 'CASE-123');
1031
+ assert.match(transformed[3], /^email_tok_[a-f0-9]{12}$/);
1032
+ assert.match(transformed[4], /^4_tok_[a-f0-9]{12}$/);
1033
+ }
1034
+
1035
+ function testBroadFunctionKeepExactKeepsNestedFreeTextExactUntilReviewed() {
1036
+ const policy = policyFromStatements([
1037
+ {
1038
+ sid: 'function-keep-return-container',
1039
+ when: {
1040
+ scope: 'FUNCTION',
1041
+ selector: 'fn:IntegrationsService.runDataLabDrillForTask',
1042
+ target: 'trace.returnValue',
1043
+ },
1044
+ apply: { action: 'KEEP_EXACT' },
1045
+ meta: { priority: 1 },
1046
+ },
1047
+ ]);
1048
+
1049
+ const transformed = applyRuntimePrivacyPolicy(
1050
+ policy,
1051
+ 'trace.returnValue',
1052
+ {
1053
+ status: 'failed',
1054
+ safeOrderId: 'ORD-123',
1055
+ statusNote: 'Manual review owner Jane Security can debug ORD-123, but provider token ghp_abcdefghijklmnopqrstuvwxyz1234567890 must never be logged raw.',
1056
+ },
1057
+ {
1058
+ appId: 'APP_test',
1059
+ trace: { fn: 'IntegrationsService.runDataLabDrillForTask' },
1060
+ },
1061
+ );
1062
+
1063
+ assert.strictEqual(transformed.status, 'failed');
1064
+ assert.strictEqual(transformed.safeOrderId, 'ORD-123');
1065
+ assert.strictEqual(
1066
+ transformed.statusNote,
1067
+ 'Manual review owner Jane Security can debug ORD-123, but provider token ghp_abcdefghijklmnopqrstuvwxyz1234567890 must never be logged raw.',
1068
+ );
1069
+ }
1070
+
1071
+ function testRawHeaderTimestampsAreNotTreatedAsCards() {
1072
+ const input = {
1073
+ rawHeaders: [
1074
+ 'X-Bug-Request-Start',
1075
+ '1777157149184',
1076
+ 'X-Repro-Request-Rid',
1077
+ '1777157149184-2gctv',
1078
+ 'X-Safe-Order-Id',
1079
+ 'ORD-123',
1080
+ ],
1081
+ };
1082
+
1083
+ const transformed = applyRuntimePrivacyPolicy(null, 'trace.args', input, { appId: 'APP_test' });
1084
+
1085
+ assert.deepStrictEqual(transformed.rawHeaders, input.rawHeaders);
1086
+ }
1087
+
1088
+ function testKafkaTimestampsAreNotTreatedAsCards() {
1089
+ const input = [{
1090
+ message: {
1091
+ timestamp: '1777161230133',
1092
+ batchContext: {
1093
+ firstTimestamp: '1777161230133',
1094
+ maxTimestamp: '1777161230142',
1095
+ },
1096
+ },
1097
+ }];
1098
+
1099
+ const transformed = applyRuntimePrivacyPolicy(null, 'trace.args', input, { appId: 'APP_test' });
1100
+
1101
+ assert.deepStrictEqual(transformed, input);
1102
+ }
1103
+
1104
+ function testFreeTextStillRedactsKnownSensitiveValues() {
1105
+ const text = 'Payment failed for john@example.com with card 4242 4242 4242 4242 and authorization Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA==';
1106
+ const transformed = applyRuntimePrivacyPolicy(null, 'trace.returnValue', text, { appId: 'APP_test' });
1107
+
1108
+ assert(!transformed.includes('john@example.com'), transformed);
1109
+ assert(!transformed.includes('4242 4242 4242 4242'), transformed);
1110
+ assert(!transformed.includes('Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA=='), transformed);
1111
+ assert.match(transformed, /email_tok_[a-f0-9]{12}/);
1112
+ assert(transformed.includes('[credit-card]'), transformed);
1113
+ assert(transformed.includes('[auth-token]'), transformed);
1114
+ }
1115
+
1116
+ async function testAuthLikeNestedFieldsDropWholeValueAndKeepReadableSpacing() {
1117
+ const input = {
1118
+ debugOverride: {
1119
+ headerAuthorization: 'Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA==',
1120
+ },
1121
+ message: 'Payment failed for john@example.com on order ORD-123 with card 4242 4242 4242 4242 and authorization Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA==',
1122
+ safeFeatureFlag: 'privacy-policy-v2',
1123
+ safeQueue: 'risk-review-high',
1124
+ safeRegion: 'us-east-1',
1125
+ workflowStage: 'provider-callback-review',
1126
+ };
1127
+
1128
+ const transformed = await applyRuntimePrivacyPolicyAsync(null, 'db.query', input, {
1129
+ appId: 'APP_test',
1130
+ appSecret: 'secret',
1131
+ });
1132
+
1133
+ assert.strictEqual(transformed.debugOverride.headerAuthorization, '[dropped]');
1134
+ assert.match(
1135
+ transformed.message,
1136
+ /^Payment failed for email_tok_[a-f0-9]{12} on order ORD-123 with card \[credit-card\] and authorization \[auth-token\]$/,
1137
+ );
1138
+ assert.strictEqual(transformed.safeFeatureFlag, 'privacy-policy-v2');
1139
+ assert.strictEqual(transformed.safeQueue, 'risk-review-high');
1140
+ assert.strictEqual(transformed.safeRegion, 'us-east-1');
1141
+ assert.strictEqual(transformed.workflowStage, 'provider-callback-review');
1142
+ }
1143
+
1144
+ function testKnownTextPolicyNormalizesGluedSlots() {
1145
+ const policy = policyFromStatements([
1146
+ {
1147
+ sid: 'known-text',
1148
+ when: {
1149
+ scope: 'FUNCTION',
1150
+ selector: 'fn:formatFailure',
1151
+ target: 'trace.returnValue',
1152
+ },
1153
+ apply: {
1154
+ action: 'KEEP_EXACT',
1155
+ textPolicy: {
1156
+ mode: 'KNOWN_TEMPLATE',
1157
+ fragments: [
1158
+ { kind: 'literal', text: 'Payment failed for' },
1159
+ { kind: 'slot', label: 'email', action: 'TOKENIZE' },
1160
+ { kind: 'literal', text: 'on order ' },
1161
+ { kind: 'slot', label: 'orderId', action: 'KEEP_EXACT' },
1162
+ ],
1163
+ },
1164
+ },
1165
+ meta: { priority: 1 },
1166
+ },
1167
+ ]);
1168
+
1169
+ const transformed = applyRuntimePrivacyPolicy(
1170
+ policy,
1171
+ 'trace.returnValue',
1172
+ 'Payment failed forjohn@example.comon order ORD-123',
1173
+ { appId: 'APP_test', trace: { fn: 'formatFailure' } },
1174
+ );
1175
+
1176
+ assert.match(transformed, /^Payment failed for email_tok_[a-f0-9]{12} on order ORD-123$/);
1177
+ }
1178
+
1179
+ function testSafePartialRawTextKeepsOperationalScalarsReadable() {
1180
+ const policy = policyFromStatements([
1181
+ {
1182
+ sid: 'raw-external-result',
1183
+ when: {
1184
+ scope: 'FIELD',
1185
+ selector: 'externalResult',
1186
+ target: 'response.body.data',
1187
+ },
1188
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'SAFE_PARTIAL_MASK' },
1189
+ meta: { priority: 1 },
1190
+ },
1191
+ ]);
1192
+
1193
+ const transformed = applyRuntimePrivacyPolicy(
1194
+ policy,
1195
+ 'response.body',
1196
+ {
1197
+ data: {
1198
+ id: '69ed2d5c585264544573ea4f',
1199
+ priority: 'high',
1200
+ riskLevel: 'high',
1201
+ safeSeverity: 'high',
1202
+ retryCount: '3',
1203
+ scenario: 'rule-drill',
1204
+ createdAt: '2026-04-29T10:24:40.123Z',
1205
+ reference: 'RLD-MOJZF582-SMS7QG',
1206
+ statusNote: 'Manual review owner Jane Security can debug RLD-MOJZF582-SMS7QG, but provider authorization Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA== must never be logged raw.',
1207
+ customerEmail: 'john@example.com',
1208
+ webhookSecret: 'whsec_abcdefghijklmnopqrstuvwxyz',
1209
+ },
1210
+ },
1211
+ { appId: 'APP_test', routeKey: 'POST /api/external-result' },
1212
+ );
1213
+
1214
+ assert.strictEqual(transformed.data.id, '69ed2d5c585264544573ea4f');
1215
+ assert.strictEqual(transformed.data.priority, 'high');
1216
+ assert.strictEqual(transformed.data.riskLevel, 'high');
1217
+ assert.strictEqual(transformed.data.safeSeverity, 'high');
1218
+ assert.strictEqual(transformed.data.retryCount, '3');
1219
+ assert.strictEqual(transformed.data.scenario, 'rule-drill');
1220
+ assert.strictEqual(transformed.data.createdAt, '2026-04-29T10:24:40.123Z');
1221
+ assert.strictEqual(transformed.data.reference, 'RLD-MOJZF582-SMS7QG');
1222
+ assert(!transformed.data.statusNote.includes('Jane Security'), transformed.data.statusNote);
1223
+ assert(!transformed.data.statusNote.includes('Bearer QWxhZGRpbjpPcGVuU2VzYW1lMTIzNA=='), transformed.data.statusNote);
1224
+ assert.match(transformed.data.customerEmail, /^email_tok_[a-f0-9]{12}$/);
1225
+ assert.strictEqual(transformed.data.webhookSecret, '[dropped]');
1226
+ }
1227
+
1228
+ function testDescendantRawTextPolicyProvenanceFollowsCopiedObjectsAndSerializedValues() {
1229
+ clearRuntimePrivacyProvenance();
1230
+ const policy = policyFromStatementsAndRawTextHints([
1231
+ {
1232
+ sid: 'source-external-drill-response',
1233
+ when: {
1234
+ scope: 'FIELD',
1235
+ selector: 'externalDrillResponse',
1236
+ target: 'response.body.data',
1237
+ },
1238
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'REGEX_ASSISTED_EXACT' },
1239
+ meta: { priority: 1 },
1240
+ },
1241
+ {
1242
+ sid: 'scenario-remains-operational-on-db-copy',
1243
+ when: {
1244
+ scope: 'FIELD',
1245
+ selector: 'scenario',
1246
+ target: 'db.query.doc.payload.metadata.scenario',
1247
+ },
1248
+ apply: { action: 'KEEP_EXACT' },
1249
+ meta: { priority: 2 },
1250
+ },
1251
+ ], [
1252
+ {
1253
+ name: 'Opaque diagnostic code',
1254
+ scope: 'RAW_TEXT_ONLY',
1255
+ action: 'TOKENIZE',
1256
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
1257
+ tokenLabel: 'opaqueDiagnostic',
1258
+ },
1259
+ ]);
1260
+
1261
+ const drill = {
1262
+ id: '69ed2d5c585264544573ea4f',
1263
+ status: 'blocked',
1264
+ metadata: {
1265
+ opaqueDiagnostic: 'ZXQ9SIGNALLAB9911KLM',
1266
+ scenario: 'security-drill',
1267
+ supportEmail: 'support@example.com',
1268
+ },
1269
+ providerMessage: 'Provider returned ZXQ9SIGNALLAB9911KLM for john@example.com and left status blocked',
1270
+ };
1271
+
1272
+ const source = applyRuntimePrivacyPolicy(
1273
+ policy,
1274
+ 'response.body',
1275
+ { data: drill, success: true },
1276
+ { appId: 'APP_test', routeKey: 'POST /api/external-drill' },
1277
+ );
1278
+
1279
+ assert.strictEqual(source.success, true);
1280
+ assert.strictEqual(typeof source.data, 'object');
1281
+ assert.strictEqual(source.data.id, '69ed2d5c585264544573ea4f');
1282
+ assert.strictEqual(source.data.status, 'blocked');
1283
+ assert.strictEqual(source.data.metadata.scenario, 'security-drill');
1284
+ assert.match(source.data.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1285
+ assert.match(source.data.metadata.supportEmail, /^email_tok_[a-f0-9]{12}$/);
1286
+ assert.match(source.data.providerMessage, /^Provider returned opaqueDiagnostic_tok_[a-f0-9]{12} for email_tok_[a-f0-9]{12} and left status blocked$/);
1287
+
1288
+ const dbCopy = applyRuntimePrivacyPolicy(
1289
+ policy,
1290
+ 'db.query',
1291
+ { doc: { payload: drill } },
1292
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'create' } },
1293
+ );
1294
+
1295
+ assert.strictEqual(typeof dbCopy.doc.payload, 'object');
1296
+ assert.strictEqual(dbCopy.doc.payload.id, '69ed2d5c585264544573ea4f');
1297
+ assert.strictEqual(dbCopy.doc.payload.status, 'blocked');
1298
+ assert.strictEqual(dbCopy.doc.payload.metadata.scenario, 'security-drill');
1299
+ assert.match(dbCopy.doc.payload.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1300
+ assert.match(dbCopy.doc.payload.metadata.supportEmail, /^email_tok_[a-f0-9]{12}$/);
1301
+ assert.match(dbCopy.doc.payload.providerMessage, /^Provider returned opaqueDiagnostic_tok_[a-f0-9]{12} for email_tok_[a-f0-9]{12} and left status blocked$/);
1302
+
1303
+ const redisCopy = applyRuntimePrivacyPolicy(
1304
+ policy,
1305
+ 'db.query',
1306
+ { args: ['cache:key', JSON.stringify(drill)] },
1307
+ { appId: 'APP_test', db: { type: 'redis', collection: 'redis', op: 'set' } },
1308
+ );
1309
+ const parsed = JSON.parse(redisCopy.args[1]);
1310
+
1311
+ assert.strictEqual(parsed.id, '69ed2d5c585264544573ea4f');
1312
+ assert.strictEqual(parsed.status, 'blocked');
1313
+ assert.strictEqual(parsed.metadata.scenario, 'security-drill');
1314
+ assert.match(parsed.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1315
+ assert.match(parsed.metadata.supportEmail, /^email_tok_[a-f0-9]{12}$/);
1316
+ assert.match(parsed.providerMessage, /^Provider returned opaqueDiagnostic_tok_[a-f0-9]{12} for email_tok_[a-f0-9]{12} and left status blocked$/);
1317
+ clearRuntimePrivacyProvenance();
1318
+ }
1319
+
1320
+ function testInheritedRegexAssistedFallbackBeatsChildSafePartialMask() {
1321
+ clearRuntimePrivacyProvenance();
1322
+ const policy = policyFromStatementsAndRawTextHints([
1323
+ {
1324
+ sid: 'reviewed-payload-boundary',
1325
+ when: {
1326
+ scope: 'FIELD',
1327
+ selector: 'PaymentCommunicationLog.payload',
1328
+ target: 'db.query.doc.payload',
1329
+ },
1330
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'REGEX_ASSISTED_EXACT' },
1331
+ meta: { priority: 1 },
1332
+ },
1333
+ {
1334
+ sid: 'generic-provider-payload-fallback',
1335
+ when: {
1336
+ scope: 'FIELD',
1337
+ selector: 'providerPayload',
1338
+ target: 'db.query.doc.payload.providerPayload',
1339
+ },
1340
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'SAFE_PARTIAL_MASK' },
1341
+ meta: { priority: 2 },
1342
+ },
1343
+ ], [
1344
+ {
1345
+ name: 'Customer loyalty tier',
1346
+ scope: 'RAW_TEXT_ONLY',
1347
+ action: 'TOKENIZE',
1348
+ regex: '\\bgold\\b',
1349
+ tokenLabel: 'loyaltyTier',
1350
+ },
1351
+ ]);
1352
+
1353
+ const transformed = applyRuntimePrivacyPolicy(
1354
+ policy,
1355
+ 'db.query',
1356
+ {
1357
+ doc: {
1358
+ payload: {
1359
+ providerPayload: {
1360
+ customer: {
1361
+ loyaltyTier: 'gold',
1362
+ note: 'customer tier is gold',
1363
+ },
1364
+ status: 'declined',
1365
+ },
1366
+ },
1367
+ },
1368
+ },
1369
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'create' } },
1370
+ );
1371
+
1372
+ assert.match(transformed.doc.payload.providerPayload.customer.loyaltyTier, /^loyaltyTier_tok_[a-f0-9]{12}$/);
1373
+ assert.match(transformed.doc.payload.providerPayload.customer.note, /^customer tier is loyaltyTier_tok_[a-f0-9]{12}$/);
1374
+ assert.strictEqual(transformed.doc.payload.providerPayload.status, 'declined');
1375
+ assert(!JSON.stringify(transformed).includes('"gold"'), JSON.stringify(transformed));
1376
+ assert(!JSON.stringify(transformed).includes('"g..d"'), JSON.stringify(transformed));
1377
+ clearRuntimePrivacyProvenance();
1378
+ }
1379
+
1380
+ function testInheritedRegexAssistedFallbackBeatsSerializedSafePartialMask() {
1381
+ clearRuntimePrivacyProvenance();
1382
+ const policy = policyFromStatementsAndRawTextHints([
1383
+ {
1384
+ sid: 'reviewed-payload-boundary',
1385
+ when: {
1386
+ scope: 'FIELD',
1387
+ selector: 'PaymentCommunicationLog.payload',
1388
+ target: 'db.query.doc.payload',
1389
+ },
1390
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'REGEX_ASSISTED_EXACT' },
1391
+ meta: { priority: 1 },
1392
+ },
1393
+ {
1394
+ sid: 'generic-serialized-provider-payload-fallback',
1395
+ when: {
1396
+ scope: 'FIELD',
1397
+ selector: 'serializedProviderPayload',
1398
+ target: 'db.query.doc.payload.serializedProviderPayload',
1399
+ },
1400
+ apply: { action: 'SUMMARIZE', rawTextMode: 'SAFE_PARTIAL_MASK' },
1401
+ meta: { priority: 2 },
1402
+ },
1403
+ ], [
1404
+ {
1405
+ name: 'Customer loyalty tier',
1406
+ scope: 'RAW_TEXT_ONLY',
1407
+ action: 'TOKENIZE',
1408
+ regex: '\\bgold\\b',
1409
+ tokenLabel: 'loyaltyTier',
1410
+ },
1411
+ ]);
1412
+
1413
+ const transformed = applyRuntimePrivacyPolicy(
1414
+ policy,
1415
+ 'db.query',
1416
+ {
1417
+ doc: {
1418
+ payload: {
1419
+ serializedProviderPayload: JSON.stringify({
1420
+ providerPayload: {
1421
+ customer: {
1422
+ loyaltyTier: 'gold',
1423
+ },
1424
+ providerText: 'tier gold accepted',
1425
+ status: 'declined',
1426
+ },
1427
+ }),
1428
+ },
1429
+ },
1430
+ },
1431
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'create' } },
1432
+ );
1433
+ const parsed = JSON.parse(transformed.doc.payload.serializedProviderPayload);
1434
+
1435
+ assert.match(parsed.providerPayload.customer.loyaltyTier, /^loyaltyTier_tok_[a-f0-9]{12}$/);
1436
+ assert.match(parsed.providerPayload.providerText, /^tier loyaltyTier_tok_[a-f0-9]{12} accepted$/);
1437
+ assert.strictEqual(parsed.providerPayload.status, 'declined');
1438
+ assert(!transformed.doc.payload.serializedProviderPayload.includes('"gold"'), transformed.doc.payload.serializedProviderPayload);
1439
+ assert(!transformed.doc.payload.serializedProviderPayload.includes('"g..d"'), transformed.doc.payload.serializedProviderPayload);
1440
+ clearRuntimePrivacyProvenance();
1441
+ }
1442
+
1443
+ function testSafePartialMaskStillAppliesWithoutInheritedRegexBoundary() {
1444
+ clearRuntimePrivacyProvenance();
1445
+ const policy = policyFromStatementsAndRawTextHints([
1446
+ {
1447
+ sid: 'generic-provider-payload-fallback',
1448
+ when: {
1449
+ scope: 'FIELD',
1450
+ selector: 'providerPayload',
1451
+ target: 'db.query.doc.payload.providerPayload',
1452
+ },
1453
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'SAFE_PARTIAL_MASK' },
1454
+ meta: { priority: 1 },
1455
+ },
1456
+ ], [
1457
+ {
1458
+ name: 'Customer loyalty tier',
1459
+ scope: 'RAW_TEXT_ONLY',
1460
+ action: 'TOKENIZE',
1461
+ regex: '\\bgold\\b',
1462
+ tokenLabel: 'loyaltyTier',
1463
+ },
1464
+ ]);
1465
+
1466
+ const transformed = applyRuntimePrivacyPolicy(
1467
+ policy,
1468
+ 'db.query',
1469
+ {
1470
+ doc: {
1471
+ payload: {
1472
+ providerPayload: {
1473
+ customer: {
1474
+ loyaltyTier: 'gold',
1475
+ },
1476
+ },
1477
+ },
1478
+ },
1479
+ },
1480
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'create' } },
1481
+ );
1482
+
1483
+ assert.strictEqual(transformed.doc.payload.providerPayload.customer.loyaltyTier, 'g..d');
1484
+ assert(!JSON.stringify(transformed).includes('loyaltyTier_tok_'), JSON.stringify(transformed));
1485
+ clearRuntimePrivacyProvenance();
1486
+ }
1487
+
1488
+ function testCopiedKafkaPayloadKeepsInheritedRegexOverChildSafePartialMask() {
1489
+ clearRuntimePrivacyProvenance();
1490
+ const policy = policyFromStatementsAndRawTextHints([
1491
+ {
1492
+ sid: 'source-external-drill-response',
1493
+ when: {
1494
+ scope: 'FIELD',
1495
+ selector: 'externalDrillResponse',
1496
+ target: 'response.body.data',
1497
+ },
1498
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'REGEX_ASSISTED_EXACT' },
1499
+ meta: { priority: 1 },
1500
+ },
1501
+ {
1502
+ sid: 'generic-kafka-payment-provider-payload-fallback',
1503
+ when: {
1504
+ scope: 'FIELD',
1505
+ selector: 'providerPayload',
1506
+ target: 'trace.args[0].messages[].value.payment.providerPayload',
1507
+ },
1508
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'SAFE_PARTIAL_MASK' },
1509
+ meta: { priority: 2 },
1510
+ },
1511
+ ], [
1512
+ {
1513
+ name: 'Customer loyalty tier',
1514
+ scope: 'RAW_TEXT_ONLY',
1515
+ action: 'TOKENIZE',
1516
+ regex: '\\bgold\\b',
1517
+ tokenLabel: 'loyaltyTier',
1518
+ },
1519
+ ]);
1520
+
1521
+ const drill = {
1522
+ id: '69ed2d5c585264544573ea4f',
1523
+ providerPayload: {
1524
+ customer: {
1525
+ loyaltyTier: 'gold',
1526
+ },
1527
+ providerText: 'tier gold accepted',
1528
+ },
1529
+ };
1530
+
1531
+ applyRuntimePrivacyPolicy(
1532
+ policy,
1533
+ 'response.body',
1534
+ { data: drill },
1535
+ { appId: 'APP_test', routeKey: 'POST /api/external-drill' },
1536
+ );
1537
+
1538
+ const transformed = applyRuntimePrivacyPolicy(
1539
+ policy,
1540
+ 'trace.args',
1541
+ [{ messages: [{ value: { payment: drill } }] }],
1542
+ { appId: 'APP_test', trace: { fn: 'producer.send' } },
1543
+ );
1544
+ const payment = transformed[0].messages[0].value.payment;
1545
+
1546
+ assert.match(payment.providerPayload.customer.loyaltyTier, /^loyaltyTier_tok_[a-f0-9]{12}$/);
1547
+ assert.match(payment.providerPayload.providerText, /^tier loyaltyTier_tok_[a-f0-9]{12} accepted$/);
1548
+ assert(!JSON.stringify(transformed).includes('"gold"'), JSON.stringify(transformed));
1549
+ assert(!JSON.stringify(transformed).includes('"g..d"'), JSON.stringify(transformed));
1550
+ clearRuntimePrivacyProvenance();
1551
+ }
1552
+
1553
+ function testKafkaOpaqueDiagnosticCopiesUseSameLeafRegexProtection() {
1554
+ clearRuntimePrivacyProvenance();
1555
+ const policy = policyFromStatementsAndRawTextHints([
1556
+ {
1557
+ sid: 'source-opaque-diagnostic',
1558
+ when: {
1559
+ scope: 'FIELD',
1560
+ selector: 'opaqueDiagnostic',
1561
+ target: 'response.body.data.metadata.opaqueDiagnostic',
1562
+ },
1563
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
1564
+ meta: { priority: 1 },
1565
+ },
1566
+ {
1567
+ sid: 'copied-kafka-opaque-diagnostic',
1568
+ when: {
1569
+ scope: 'FIELD',
1570
+ selector: 'opaqueDiagnostic',
1571
+ target: 'trace.args[0].payment.metadata.opaqueDiagnostic|trace.args[0].messages[].value.payment.metadata.opaqueDiagnostic',
1572
+ },
1573
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
1574
+ meta: { priority: 2 },
1575
+ },
1576
+ ], [
1577
+ {
1578
+ name: 'Opaque diagnostic detector',
1579
+ scope: 'RAW_TEXT_ONLY',
1580
+ action: 'TOKENIZE',
1581
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
1582
+ tokenLabel: 'opaqueDiagnostic',
1583
+ },
1584
+ ]);
1585
+
1586
+ const opaqueDiagnostic = 'ZXQ9DATALAB9911KLM';
1587
+ const transformed = applyRuntimePrivacyPolicy(
1588
+ policy,
1589
+ 'trace.args',
1590
+ [
1591
+ {
1592
+ payment: {
1593
+ metadata: {
1594
+ opaqueDiagnostic,
1595
+ },
1596
+ },
1597
+ messages: [
1598
+ {
1599
+ value: {
1600
+ payment: {
1601
+ metadata: {
1602
+ opaqueDiagnostic,
1603
+ },
1604
+ },
1605
+ },
1606
+ },
1607
+ {
1608
+ value: JSON.stringify({
1609
+ payment: {
1610
+ metadata: {
1611
+ opaqueDiagnostic,
1612
+ },
1613
+ },
1614
+ }),
1615
+ },
1616
+ ],
1617
+ },
1618
+ ],
1619
+ { appId: 'APP_test', trace: { fn: 'producer.send' } },
1620
+ );
1621
+
1622
+ assert.match(transformed[0].payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1623
+ assert.match(transformed[0].messages[0].value.payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1624
+ const parsedKafkaValue = JSON.parse(transformed[0].messages[1].value);
1625
+ assert.match(parsedKafkaValue.payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1626
+ assert(!JSON.stringify(transformed).includes(opaqueDiagnostic), JSON.stringify(transformed));
1627
+ clearRuntimePrivacyProvenance();
1628
+ }
1629
+
1630
+ function testOpaqueDiagnosticPayloadCopyTargetsTokenizeRuntimeSurfaces() {
1631
+ clearRuntimePrivacyProvenance();
1632
+ const policy = policyFromStatements([
1633
+ {
1634
+ sid: 'opaque-diagnostic-runtime-copies',
1635
+ when: {
1636
+ scope: 'FIELD',
1637
+ selector: 'opaqueDiagnostic',
1638
+ target: [
1639
+ 'response.body.data.metadata.opaqueDiagnostic',
1640
+ 'db.query.doc.payload.metadata.opaqueDiagnostic',
1641
+ 'db.after.payload.metadata.opaqueDiagnostic',
1642
+ 'trace.args[0].payload.metadata.opaqueDiagnostic',
1643
+ 'trace.returnValue.payload.metadata.opaqueDiagnostic',
1644
+ 'db.query.doc.payload.payment.metadata.opaqueDiagnostic',
1645
+ 'db.after.payload.payment.metadata.opaqueDiagnostic',
1646
+ 'trace.args[0].payload.payment.metadata.opaqueDiagnostic',
1647
+ 'trace.returnValue.payload.payment.metadata.opaqueDiagnostic',
1648
+ ].join('|'),
1649
+ },
1650
+ apply: { action: 'TOKENIZE' },
1651
+ meta: { priority: 1 },
1652
+ },
1653
+ ]);
1654
+ const opaqueDiagnostic = 'ZXQ9DATALAB9911KLM';
1655
+
1656
+ const response = applyRuntimePrivacyPolicy(
1657
+ policy,
1658
+ 'response.body',
1659
+ { data: { metadata: { opaqueDiagnostic } } },
1660
+ { appId: 'APP_test' },
1661
+ );
1662
+ const dbQuery = applyRuntimePrivacyPolicy(
1663
+ policy,
1664
+ 'db.query',
1665
+ {
1666
+ doc: {
1667
+ payload: {
1668
+ metadata: { opaqueDiagnostic },
1669
+ payment: { metadata: { opaqueDiagnostic } },
1670
+ },
1671
+ },
1672
+ },
1673
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'insert' } },
1674
+ );
1675
+ const dbAfter = applyRuntimePrivacyPolicy(
1676
+ policy,
1677
+ 'db.after',
1678
+ {
1679
+ payload: {
1680
+ metadata: { opaqueDiagnostic },
1681
+ payment: { metadata: { opaqueDiagnostic } },
1682
+ },
1683
+ },
1684
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'insert' } },
1685
+ );
1686
+ const traceArgs = applyRuntimePrivacyPolicy(
1687
+ policy,
1688
+ 'trace.args',
1689
+ [
1690
+ {
1691
+ payload: {
1692
+ metadata: { opaqueDiagnostic },
1693
+ payment: { metadata: { opaqueDiagnostic } },
1694
+ },
1695
+ },
1696
+ ],
1697
+ { appId: 'APP_test', trace: { fn: 'emitCommunicationLog' } },
1698
+ );
1699
+ const traceReturnValue = applyRuntimePrivacyPolicy(
1700
+ policy,
1701
+ 'trace.returnValue',
1702
+ {
1703
+ payload: {
1704
+ metadata: { opaqueDiagnostic },
1705
+ payment: { metadata: { opaqueDiagnostic } },
1706
+ },
1707
+ },
1708
+ { appId: 'APP_test', trace: { fn: 'emitCommunicationLog' } },
1709
+ );
1710
+
1711
+ assert.match(response.data.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1712
+ assert.match(dbQuery.doc.payload.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1713
+ assert.match(dbQuery.doc.payload.payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1714
+ assert.match(dbAfter.payload.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1715
+ assert.match(dbAfter.payload.payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1716
+ assert.match(traceArgs[0].payload.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1717
+ assert.match(traceArgs[0].payload.payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1718
+ assert.match(traceReturnValue.payload.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1719
+ assert.match(traceReturnValue.payload.payment.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1720
+ assert(!JSON.stringify({ response, dbQuery, dbAfter, traceArgs, traceReturnValue }).includes(opaqueDiagnostic));
1721
+ clearRuntimePrivacyProvenance();
1722
+ }
1723
+
1724
+ function testOpaqueCorrelationPatternTokenizesMissedRuntimeCopies() {
1725
+ clearRuntimePrivacyProvenance();
1726
+ const policy = policyFromStatements([
1727
+ {
1728
+ sid: 'baseline-opaque-correlation-values',
1729
+ when: {
1730
+ scope: 'PATTERN',
1731
+ selector: 'pattern:baseline-opaque-correlation-values',
1732
+ target: 'response.body|trace.args|trace.returnValue|db.query|db.after|db.before',
1733
+ pattern: '(?i)(^|\\.)(opaque[A-Za-z0-9_]*(Id|Token|Trace|Diagnostic)|[A-Za-z0-9_]*(OpaqueId|OpaqueToken|OpaqueTrace|OpaqueDiagnostic))$',
1734
+ },
1735
+ apply: { action: 'TOKENIZE' },
1736
+ meta: { priority: 1 },
1737
+ },
1738
+ ]);
1739
+ const opaqueDiagnostic = 'ZXQ9SIGNALLAB9911KLM';
1740
+
1741
+ const transformed = applyRuntimePrivacyPolicy(
1742
+ policy,
1743
+ 'trace.args',
1744
+ [
1745
+ {
1746
+ payload: {
1747
+ metadata: { opaqueDiagnostic },
1748
+ payment: { metadata: { opaqueTraceId: opaqueDiagnostic } },
1749
+ },
1750
+ },
1751
+ ],
1752
+ { appId: 'APP_test', trace: { fn: 'opaqueFlow' } },
1753
+ );
1754
+
1755
+ assert.match(transformed[0].payload.metadata.opaqueDiagnostic, /^opaqueDiagnostic_tok_[a-f0-9]{12}$/);
1756
+ assert.match(transformed[0].payload.payment.metadata.opaqueTraceId, /^opaqueTraceId_tok_[a-f0-9]{12}$/);
1757
+ assert(!JSON.stringify(transformed).includes(opaqueDiagnostic), JSON.stringify(transformed));
1758
+ clearRuntimePrivacyProvenance();
1759
+ }
1760
+
1761
+ function testDbWriteQueryPolicySeedsAfterSnapshotProvenance() {
1762
+ clearRuntimePrivacyProvenance();
1763
+ const policy = policyFromStatementsAndRawTextHints([
1764
+ {
1765
+ sid: 'communication-log-payload',
1766
+ when: {
1767
+ scope: 'SCHEMA',
1768
+ selector: 'CommunicationLog.payload',
1769
+ target: 'db.query.doc.payload',
1770
+ },
1771
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'REGEX_ASSISTED_EXACT' },
1772
+ meta: { priority: 1 },
1773
+ },
1774
+ ], [
1775
+ {
1776
+ name: 'Customer loyalty tier',
1777
+ scope: 'RAW_TEXT_ONLY',
1778
+ action: 'TOKENIZE',
1779
+ regex: '\\bgold\\b',
1780
+ tokenLabel: 'loyaltyTier',
1781
+ },
1782
+ ]);
1783
+
1784
+ const savedDocument = {
1785
+ payload: {
1786
+ payment: {
1787
+ providerPayload: {
1788
+ customer: {
1789
+ loyaltyTier: 'gold',
1790
+ },
1791
+ },
1792
+ },
1793
+ },
1794
+ };
1795
+
1796
+ applyRuntimePrivacyPolicy(
1797
+ policy,
1798
+ 'db.query',
1799
+ { doc: savedDocument },
1800
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'insert' } },
1801
+ );
1802
+
1803
+ const transformedAfter = applyRuntimePrivacyPolicy(
1804
+ policy,
1805
+ 'db.after',
1806
+ savedDocument,
1807
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'insert' } },
1808
+ );
1809
+
1810
+ assert.match(transformedAfter.payload.payment.providerPayload.customer.loyaltyTier, /^loyaltyTier_tok_[a-f0-9]{12}$/);
1811
+ assert(!JSON.stringify(transformedAfter).includes('"gold"'), JSON.stringify(transformedAfter));
1812
+ clearRuntimePrivacyProvenance();
1813
+ }
1814
+
1815
+ function testDbWriteQueryPolicySeedsSerializedKafkaTraceProvenance() {
1816
+ clearRuntimePrivacyProvenance();
1817
+ const policy = policyFromStatementsAndRawTextHints([
1818
+ {
1819
+ sid: 'communication-log-payload',
1820
+ when: {
1821
+ scope: 'SCHEMA',
1822
+ selector: 'CommunicationLog.payload',
1823
+ target: 'db.query.doc.payload',
1824
+ },
1825
+ apply: { action: 'KEEP_EXACT', descendantRawTextMode: 'REGEX_ASSISTED_EXACT' },
1826
+ meta: { priority: 1 },
1827
+ },
1828
+ ], [
1829
+ {
1830
+ name: 'Customer loyalty tier',
1831
+ scope: 'RAW_TEXT_ONLY',
1832
+ action: 'TOKENIZE',
1833
+ regex: '\\bgold\\b',
1834
+ tokenLabel: 'loyaltyTier',
1835
+ },
1836
+ ]);
1837
+
1838
+ const envelope = {
1839
+ payment: {
1840
+ providerPayload: {
1841
+ customer: {
1842
+ loyaltyTier: 'gold',
1843
+ },
1844
+ },
1845
+ },
1846
+ };
1847
+
1848
+ applyRuntimePrivacyPolicy(
1849
+ policy,
1850
+ 'db.query',
1851
+ { doc: { payload: envelope } },
1852
+ { appId: 'APP_test', db: { type: 'mongo', collection: 'communicationlogs', op: 'insert' } },
1853
+ );
1854
+
1855
+ const transformedTraceString = applyRuntimePrivacyPolicy(
1856
+ policy,
1857
+ 'trace.returnValue',
1858
+ JSON.stringify(envelope),
1859
+ { appId: 'APP_test', trace: { fn: 'message.value.toString' } },
1860
+ );
1861
+
1862
+ assert.match(transformedTraceString, /loyaltyTier_tok_[a-f0-9]{12}/);
1863
+ assert(!transformedTraceString.includes('"gold"'), transformedTraceString);
1864
+ clearRuntimePrivacyProvenance();
1865
+ }
1866
+
1867
+ function testTraceRawMessageRegexRuleBeatsFunctionParameterSummary() {
1868
+ clearRuntimePrivacyProvenance();
1869
+ const policy = policyFromStatementsAndRawTextHints([
1870
+ {
1871
+ sid: 'kafka-raw-message',
1872
+ when: {
1873
+ scope: 'FIELD',
1874
+ selector: 'rawMessage',
1875
+ target: 'trace.args[2]',
1876
+ },
1877
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
1878
+ meta: { priority: 25, review: { rawTextHintNames: ['Raw message opaque detector'] } },
1879
+ },
1880
+ {
1881
+ sid: 'record-consumed-event-container',
1882
+ when: {
1883
+ scope: 'FUNCTION',
1884
+ selector: 'fn:PrivacyLabDrillsService.recordConsumedEvent',
1885
+ target: 'trace.args',
1886
+ },
1887
+ apply: { action: 'KEEP_EXACT' },
1888
+ meta: { priority: 51 },
1889
+ },
1890
+ {
1891
+ sid: 'record-consumed-event-raw-message-param',
1892
+ when: {
1893
+ scope: 'FUNCTION',
1894
+ selector: 'fn:PrivacyLabDrillsService.recordConsumedEvent',
1895
+ target: 'trace.args[2]',
1896
+ },
1897
+ apply: { action: 'SUMMARIZE' },
1898
+ meta: { priority: 113 },
1899
+ },
1900
+ ], [
1901
+ {
1902
+ name: 'Raw narrative opaque detector',
1903
+ scope: 'RAW_TEXT_ONLY',
1904
+ action: 'TOKENIZE',
1905
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
1906
+ tokenLabel: 'rawNarrative',
1907
+ },
1908
+ {
1909
+ name: 'Raw message opaque detector',
1910
+ scope: 'RAW_TEXT_ONLY',
1911
+ action: 'TOKENIZE',
1912
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
1913
+ tokenLabel: 'rawMessage',
1914
+ },
1915
+ ]);
1916
+
1917
+ const opaque = 'ZXQB763FF94061E84A19KLM-TRACE-B763FF';
1918
+ const transformed = applyRuntimePrivacyPolicy(
1919
+ policy,
1920
+ 'trace.args',
1921
+ [{ eventId: 'evt-1' }, 'privacy-lab-mopvlblv', `raw message contained ${opaque}`],
1922
+ { appId: 'APP_test', trace: { fn: 'PrivacyLabDrillsService.recordConsumedEvent' } },
1923
+ );
1924
+
1925
+ assert.match(transformed[2], /^raw message contained rawMessage_tok_[a-f0-9]{12}$/);
1926
+ assert(!JSON.stringify(transformed).includes(opaque), JSON.stringify(transformed));
1927
+ clearRuntimePrivacyProvenance();
1928
+ }
1929
+
1930
+ function testRegexAssistedRawStringPolicyAppliesInsideSerializedTraceString() {
1931
+ clearRuntimePrivacyProvenance();
1932
+ const policy = policyFromStatementsAndRawTextHints([
1933
+ {
1934
+ sid: 'kafka-raw-message',
1935
+ when: {
1936
+ scope: 'FIELD',
1937
+ selector: 'rawMessage',
1938
+ target: 'trace.args[0]',
1939
+ },
1940
+ apply: { action: 'SUMMARIZE', rawTextMode: 'REGEX_ASSISTED_EXACT' },
1941
+ meta: { priority: 25, review: { rawTextHintNames: ['Raw message opaque detector'] } },
1942
+ },
1943
+ {
1944
+ sid: 'json-parse-input',
1945
+ when: {
1946
+ scope: 'FUNCTION',
1947
+ selector: 'fn:JSON.parse',
1948
+ target: 'trace.args[0]',
1949
+ },
1950
+ apply: { action: 'SUMMARIZE' },
1951
+ meta: { priority: 113 },
1952
+ },
1953
+ ], [
1954
+ {
1955
+ name: 'Raw narrative opaque detector',
1956
+ scope: 'RAW_TEXT_ONLY',
1957
+ action: 'TOKENIZE',
1958
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
1959
+ tokenLabel: 'rawNarrative',
1960
+ },
1961
+ {
1962
+ name: 'Raw message opaque detector',
1963
+ scope: 'RAW_TEXT_ONLY',
1964
+ action: 'TOKENIZE',
1965
+ regex: '\\bZXQ[0-9A-Z]{8,32}(?:-[A-Z0-9]{2,32})*\\b',
1966
+ tokenLabel: 'rawMessage',
1967
+ },
1968
+ ]);
1969
+
1970
+ const opaque = 'ZXQB763FF94061E84A19KLM-TRACE-B763FF';
1971
+ const serialized = JSON.stringify({
1972
+ providerResponse: {
1973
+ supportTranscript: `Support transcript matched trace ${opaque} while the payload was visible.`,
1974
+ status: 'received',
1975
+ },
1976
+ });
1977
+
1978
+ const transformed = applyRuntimePrivacyPolicy(
1979
+ policy,
1980
+ 'trace.args',
1981
+ [serialized],
1982
+ { appId: 'APP_test', trace: { fn: 'JSON.parse' } },
1983
+ );
1984
+ const parsed = JSON.parse(transformed[0]);
1985
+
1986
+ assert.match(
1987
+ parsed.providerResponse.supportTranscript,
1988
+ /^Support transcript matched trace rawMessage_tok_[a-f0-9]{12} while the payload was visible\.$/,
1989
+ );
1990
+ assert.strictEqual(parsed.providerResponse.status, 'received');
1991
+ assert(!JSON.stringify(transformed).includes(opaque), JSON.stringify(transformed));
1992
+ clearRuntimePrivacyProvenance();
1993
+ }
1994
+
1995
+ async function main() {
1996
+ await testSerializedJsonStringsUseNestedRulesAndFallbacks();
1997
+ await testLongSerializedJsonStringsAreTransformedBeforeTruncation();
1998
+ await testSerializedRedisPayloadTokenizesNestedReviewerIdentity();
1999
+ await testSummarizedSerializedJsonKeepsOperationalLeavesReadable();
2000
+ await testEmptyArrayBracketTargetsMatchArrayItems();
2001
+ await testKnownEvidenceMessagesApplyInsideWrappersAndSerializedPayloads();
2002
+ await testSerializedJsonIsNotDroppedAsAtomicSecretText();
2003
+ testOperationalIdsDoNotFallbackMaskOrLookLikeCreditCards();
2004
+ testPlainObjectsWithIdAreNotCollapsedToObjectId();
2005
+ testNestedIdentityFieldsUseGenericSemanticFallback();
2006
+ testObjectTokenizePreservesStructure();
2007
+ await testTopLevelKnownTextPolicyIsAcceptedInSerializedValues();
2008
+ testUnknownFreeTextLeafStaysExactWithoutExplicitRawMode();
2009
+ testRawTextRegexHintsPreserveUnmatchedTextWhenExplicitlyEnabled();
2010
+ testRawTextRegexHintsSupportMultipleActionsOnSameRawString();
2011
+ testRegexAssistedRawTextRuleBeatsSamePathSafePartialMask();
2012
+ testSyncSafePartialRawTextRunsBuiltInDetectorsBeforeMasking();
2013
+ testRawTextRegexHintsPreferCurrentPathLabel();
2014
+ testRawTextRegexHintsDoNotRunWithoutExplicitRawTextMode();
2015
+ testRegexAssistedRawTextWithoutHintsKeepsUnmatchedTextExact();
2016
+ testRawTextRegexHintsDoNotRunOnStructuredFields();
2017
+ testExactSensitiveTargetBeatsExactFunctionKeepExact();
2018
+ testBroadFunctionKeepExactKeepsNestedFreeTextExactUntilReviewed();
2019
+ testRawHeaderTimestampsAreNotTreatedAsCards();
2020
+ testKafkaTimestampsAreNotTreatedAsCards();
2021
+ testFreeTextStillRedactsKnownSensitiveValues();
2022
+ await testAuthLikeNestedFieldsDropWholeValueAndKeepReadableSpacing();
2023
+ testKnownTextPolicyNormalizesGluedSlots();
2024
+ testSafePartialRawTextKeepsOperationalScalarsReadable();
2025
+ testDescendantRawTextPolicyProvenanceFollowsCopiedObjectsAndSerializedValues();
2026
+ testInheritedRegexAssistedFallbackBeatsChildSafePartialMask();
2027
+ testInheritedRegexAssistedFallbackBeatsSerializedSafePartialMask();
2028
+ testSafePartialMaskStillAppliesWithoutInheritedRegexBoundary();
2029
+ testCopiedKafkaPayloadKeepsInheritedRegexOverChildSafePartialMask();
2030
+ testKafkaOpaqueDiagnosticCopiesUseSameLeafRegexProtection();
2031
+ testOpaqueDiagnosticPayloadCopyTargetsTokenizeRuntimeSurfaces();
2032
+ testOpaqueCorrelationPatternTokenizesMissedRuntimeCopies();
2033
+ testDbWriteQueryPolicySeedsAfterSnapshotProvenance();
2034
+ testDbWriteQueryPolicySeedsSerializedKafkaTraceProvenance();
2035
+ testTraceRawMessageRegexRuleBeatsFunctionParameterSummary();
2036
+ testRegexAssistedRawStringPolicyAppliesInsideSerializedTraceString();
2037
+ console.log('privacy runtime policy enforcement OK');
2038
+ }
2039
+
2040
+ main().catch(err => {
2041
+ console.error(err);
2042
+ process.exitCode = 1;
2043
+ });