@heroku/js-blanket 0.0.0 → 0.0.1
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.
- package/README.md +4 -1
- package/dist/.tsbuildinfo +1 -0
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/adapters/logging/generic.js +23 -0
- package/dist/cjs/adapters/logging/generic.js.map +1 -0
- package/dist/cjs/adapters/logging/generic.test.js +432 -0
- package/dist/cjs/adapters/logging/generic.test.js.map +1 -0
- package/dist/cjs/core/patterns.js +17 -0
- package/dist/cjs/core/patterns.js.map +1 -0
- package/dist/cjs/core/presets.js +116 -0
- package/dist/cjs/core/presets.js.map +1 -0
- package/dist/cjs/core/scrubber.js +260 -0
- package/dist/cjs/core/scrubber.js.map +1 -0
- package/dist/cjs/core/scrubber.test.js +392 -0
- package/dist/cjs/core/scrubber.test.js.map +1 -0
- package/dist/cjs/core/types.js +3 -0
- package/dist/cjs/core/types.js.map +1 -0
- package/dist/cjs/core/types.test.js +326 -0
- package/dist/cjs/core/types.test.js.map +1 -0
- package/dist/cjs/index.js +16 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/index.test.js +31 -0
- package/dist/cjs/index.test.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/{src/adapters/logging/generic.ts → dist/esm/adapters/logging/generic.d.ts} +1 -4
- package/dist/esm/adapters/logging/generic.js +20 -0
- package/dist/esm/adapters/logging/generic.js.map +1 -0
- package/dist/esm/adapters/logging/generic.test.d.ts +7 -0
- package/dist/esm/adapters/logging/generic.test.js +430 -0
- package/dist/esm/adapters/logging/generic.test.js.map +1 -0
- package/dist/esm/core/patterns.d.ts +4 -0
- package/dist/esm/core/patterns.js +14 -0
- package/dist/esm/core/patterns.js.map +1 -0
- package/dist/esm/core/presets.d.ts +64 -0
- package/{src/core/presets.ts → dist/esm/core/presets.js} +46 -55
- package/dist/esm/core/presets.js.map +1 -0
- package/dist/esm/core/scrubber.d.ts +131 -0
- package/dist/esm/core/scrubber.js +256 -0
- package/dist/esm/core/scrubber.js.map +1 -0
- package/dist/esm/core/scrubber.test.d.ts +1 -0
- package/dist/esm/core/scrubber.test.js +390 -0
- package/dist/esm/core/scrubber.test.js.map +1 -0
- package/dist/esm/core/types.d.ts +169 -0
- package/dist/esm/core/types.js +2 -0
- package/dist/esm/core/types.js.map +1 -0
- package/dist/esm/core/types.test.d.ts +9 -0
- package/dist/esm/core/types.test.js +324 -0
- package/dist/esm/core/types.test.js.map +1 -0
- package/{src/index.ts → dist/esm/index.d.ts} +0 -3
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.test.d.ts +1 -0
- package/dist/esm/index.test.js +29 -0
- package/dist/esm/index.test.js.map +1 -0
- package/package.json +45 -47
- package/.c8rc.json +0 -11
- package/.editorconfig +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -41
- package/.github/copilot-instructions.md +0 -117
- package/.github/workflows/ci.yml +0 -25
- package/.husky/pre-commit +0 -1
- package/.lintstagedrc.json +0 -4
- package/.tool-versions +0 -1
- package/CODEOWNERS +0 -8
- package/CODE_OF_CONDUCT.md +0 -111
- package/CONTRIBUTING.md +0 -123
- package/SECURITY.md +0 -8
- package/docs/examples/logging-integration.md +0 -736
- package/eslint.config.mjs +0 -108
- package/prettier.config.mjs +0 -10
- package/scripts/test-setup.mjs +0 -24
- package/src/adapters/logging/generic.test.ts +0 -531
- package/src/core/patterns.ts +0 -22
- package/src/core/scrubber.test.ts +0 -465
- package/src/core/scrubber.ts +0 -284
- package/src/core/types.test.ts +0 -516
- package/src/core/types.ts +0 -176
- package/src/index.test.ts +0 -41
- package/tsconfig.cjs.json +0 -12
- package/tsconfig.esm.json +0 -12
- package/tsconfig.json +0 -32
- package/tsconfig.test.json +0 -9
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { describe, it } from 'mocha';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import { Scrubber } from './scrubber.js';
|
|
4
|
+
describe('Scrubber', () => {
|
|
5
|
+
describe('Field-based scrubbing', () => {
|
|
6
|
+
it('scrubs sensitive fields at any depth', () => {
|
|
7
|
+
const scrubber = new Scrubber({
|
|
8
|
+
fields: ['access_token'],
|
|
9
|
+
});
|
|
10
|
+
const input = {
|
|
11
|
+
user: {
|
|
12
|
+
profile: {
|
|
13
|
+
settings: {
|
|
14
|
+
auth: { access_token: 'secret123' },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const { data } = scrubber.scrub(input);
|
|
20
|
+
expect(data.user.profile.settings.auth.access_token).to.equal('[SCRUBBED]');
|
|
21
|
+
});
|
|
22
|
+
it('handles case-insensitive field matching', () => {
|
|
23
|
+
const scrubber = new Scrubber({
|
|
24
|
+
fields: ['password'],
|
|
25
|
+
});
|
|
26
|
+
const input = {
|
|
27
|
+
Password: 'secret1',
|
|
28
|
+
PASSWORD: 'secret2',
|
|
29
|
+
password: 'secret3',
|
|
30
|
+
};
|
|
31
|
+
const { data } = scrubber.scrub(input);
|
|
32
|
+
expect(data.Password).to.equal('[SCRUBBED]');
|
|
33
|
+
expect(data.PASSWORD).to.equal('[SCRUBBED]');
|
|
34
|
+
expect(data.password).to.equal('[SCRUBBED]');
|
|
35
|
+
});
|
|
36
|
+
it('supports regex field patterns', () => {
|
|
37
|
+
const scrubber = new Scrubber({
|
|
38
|
+
fields: [/api[-_]?key/i], // Matches api_key, api-key, apikey (case insensitive)
|
|
39
|
+
});
|
|
40
|
+
const input = {
|
|
41
|
+
user_api_key: 'secret',
|
|
42
|
+
API_KEY_V2: 'secret',
|
|
43
|
+
myApiKeyHere: 'secret',
|
|
44
|
+
};
|
|
45
|
+
const { data } = scrubber.scrub(input);
|
|
46
|
+
expect(data.user_api_key).to.equal('[SCRUBBED]');
|
|
47
|
+
expect(data.API_KEY_V2).to.equal('[SCRUBBED]');
|
|
48
|
+
expect(data.myApiKeyHere).to.equal('[SCRUBBED]');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('Path-based scrubbing', () => {
|
|
52
|
+
it('scrubs specific paths only', () => {
|
|
53
|
+
const scrubber = new Scrubber({
|
|
54
|
+
paths: ['user.profile.email'],
|
|
55
|
+
});
|
|
56
|
+
const input = {
|
|
57
|
+
user: {
|
|
58
|
+
profile: { email: 'bob@example.com', name: 'Bob' },
|
|
59
|
+
settings: { email: 'notifications@example.com' },
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const { data } = scrubber.scrub(input);
|
|
63
|
+
expect(data.user.profile.email).to.equal('[SCRUBBED]');
|
|
64
|
+
expect(data.user.settings.email).to.equal('notifications@example.com');
|
|
65
|
+
});
|
|
66
|
+
it('scrubs array items by index', () => {
|
|
67
|
+
const scrubber = new Scrubber({
|
|
68
|
+
paths: ['users[0].password'],
|
|
69
|
+
});
|
|
70
|
+
const input = {
|
|
71
|
+
users: [
|
|
72
|
+
{ name: 'bob', password: 'secret1' },
|
|
73
|
+
{ name: 'alice', password: 'secret2' },
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
const { data } = scrubber.scrub(input);
|
|
77
|
+
expect(data.users?.[0]?.password).to.equal('[SCRUBBED]');
|
|
78
|
+
expect(data.users?.[1]?.password).to.equal('secret2');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('Pattern-based scrubbing', () => {
|
|
82
|
+
it('scrubs SSN patterns in strings', () => {
|
|
83
|
+
const scrubber = new Scrubber({
|
|
84
|
+
patterns: [/\b\d{3}-\d{2}-\d{4}\b/g],
|
|
85
|
+
});
|
|
86
|
+
const input = { message: 'User SSN is 123-45-6789' };
|
|
87
|
+
const { data } = scrubber.scrub(input);
|
|
88
|
+
expect(data.message).to.contain('[SCRUBBED]');
|
|
89
|
+
expect(data.message).not.to.contain('123-45-6789');
|
|
90
|
+
});
|
|
91
|
+
it('scrubs email patterns in strings', () => {
|
|
92
|
+
const scrubber = new Scrubber({
|
|
93
|
+
patterns: [/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g],
|
|
94
|
+
});
|
|
95
|
+
const input = { log: 'Auth failed for user@example.com' };
|
|
96
|
+
const { data } = scrubber.scrub(input);
|
|
97
|
+
expect(data.log).to.contain('[SCRUBBED]');
|
|
98
|
+
expect(data.log).not.to.contain('user@example.com');
|
|
99
|
+
});
|
|
100
|
+
it('scrubs multiple patterns in same string', () => {
|
|
101
|
+
const scrubber = new Scrubber({
|
|
102
|
+
patterns: [
|
|
103
|
+
/\b\d{3}-\d{2}-\d{4}\b/g, // SSN
|
|
104
|
+
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, // Email
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
const input = {
|
|
108
|
+
log: 'User bob@example.com has SSN 123-45-6789',
|
|
109
|
+
};
|
|
110
|
+
const { data } = scrubber.scrub(input);
|
|
111
|
+
expect(data.log).not.to.contain('bob@example.com');
|
|
112
|
+
expect(data.log).not.to.contain('123-45-6789');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('Array handling', () => {
|
|
116
|
+
it('scrubs fields across all array items', () => {
|
|
117
|
+
const scrubber = new Scrubber({
|
|
118
|
+
fields: ['password'],
|
|
119
|
+
});
|
|
120
|
+
const users = [
|
|
121
|
+
{ name: 'bob', password: 'secret' },
|
|
122
|
+
{ name: 'alice', password: 'hidden' },
|
|
123
|
+
];
|
|
124
|
+
const { data } = scrubber.scrub(users);
|
|
125
|
+
expect(data[0]?.password).to.equal('[SCRUBBED]');
|
|
126
|
+
expect(data[1]?.password).to.equal('[SCRUBBED]');
|
|
127
|
+
expect(data[0]?.name).to.equal('bob');
|
|
128
|
+
expect(data[1]?.name).to.equal('alice');
|
|
129
|
+
});
|
|
130
|
+
it('handles nested arrays', () => {
|
|
131
|
+
const scrubber = new Scrubber({
|
|
132
|
+
fields: ['api_key'],
|
|
133
|
+
});
|
|
134
|
+
const input = {
|
|
135
|
+
teams: [
|
|
136
|
+
{
|
|
137
|
+
members: [
|
|
138
|
+
{ name: 'bob', api_key: 'secret1' },
|
|
139
|
+
{ name: 'alice', api_key: 'secret2' },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
const { data } = scrubber.scrub(input);
|
|
145
|
+
expect(data.teams?.[0]?.members?.[0]?.api_key).to.equal('[SCRUBBED]');
|
|
146
|
+
expect(data.teams?.[0]?.members?.[1]?.api_key).to.equal('[SCRUBBED]');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe('Circular reference handling', () => {
|
|
150
|
+
it('handles circular references without crashing', () => {
|
|
151
|
+
const scrubber = new Scrubber({ fields: [] });
|
|
152
|
+
const input = { name: 'test' };
|
|
153
|
+
input.self = input;
|
|
154
|
+
const { data } = scrubber.scrub(input);
|
|
155
|
+
expect(data.self).to.equal('[Circular Reference]');
|
|
156
|
+
});
|
|
157
|
+
it('scrubs fields before detecting circular references', () => {
|
|
158
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
159
|
+
const input = { name: 'test', password: 'secret' };
|
|
160
|
+
input.self = input;
|
|
161
|
+
const { data } = scrubber.scrub(input);
|
|
162
|
+
expect(data.password).to.equal('[SCRUBBED]');
|
|
163
|
+
expect(data.self).to.equal('[Circular Reference]');
|
|
164
|
+
});
|
|
165
|
+
it('handles nested circular references', () => {
|
|
166
|
+
const scrubber = new Scrubber({ fields: [] });
|
|
167
|
+
const input = { name: 'test', nested: { level: 1 } };
|
|
168
|
+
input.self = input;
|
|
169
|
+
input.nested.parent = input;
|
|
170
|
+
const { data } = scrubber.scrub(input);
|
|
171
|
+
expect(data.self).to.equal('[Circular Reference]');
|
|
172
|
+
expect(data.nested.parent).to.equal('[Circular Reference]');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('Combined modes', () => {
|
|
176
|
+
it('applies field + path + pattern scrubbing together', () => {
|
|
177
|
+
const scrubber = new Scrubber({
|
|
178
|
+
fields: ['api_key'],
|
|
179
|
+
paths: ['user.email'],
|
|
180
|
+
patterns: [/\b\d{3}-\d{2}-\d{4}\b/g],
|
|
181
|
+
});
|
|
182
|
+
const input = {
|
|
183
|
+
user: {
|
|
184
|
+
email: 'bob@example.com', // Path-based
|
|
185
|
+
api_key: 'secret-key-123', // Field-based
|
|
186
|
+
},
|
|
187
|
+
log: 'SSN: 123-45-6789', // Pattern-based
|
|
188
|
+
nested: {
|
|
189
|
+
service: {
|
|
190
|
+
api_key: 'another-secret', // Field-based (any depth)
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
const { data, scrubbedPaths } = scrubber.scrub(input);
|
|
195
|
+
expect(data.user?.email).to.equal('[SCRUBBED]');
|
|
196
|
+
expect(data.user?.api_key).to.equal('[SCRUBBED]');
|
|
197
|
+
expect(data.log).not.to.contain('123-45-6789');
|
|
198
|
+
expect(data.nested?.service?.api_key).to.equal('[SCRUBBED]');
|
|
199
|
+
expect(scrubbedPaths.length).to.be.greaterThan(0);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
describe('Scrub result metadata', () => {
|
|
203
|
+
it('tracks scrubbed paths', () => {
|
|
204
|
+
const scrubber = new Scrubber({
|
|
205
|
+
fields: ['password'],
|
|
206
|
+
paths: ['user.email'],
|
|
207
|
+
});
|
|
208
|
+
const input = {
|
|
209
|
+
user: { email: 'test@example.com', password: 'secret' },
|
|
210
|
+
};
|
|
211
|
+
const result = scrubber.scrub(input);
|
|
212
|
+
expect(result.scrubbed).to.be.true;
|
|
213
|
+
expect(result.scrubbedPaths).to.include.members([
|
|
214
|
+
'user.email',
|
|
215
|
+
'user.password',
|
|
216
|
+
]);
|
|
217
|
+
});
|
|
218
|
+
it('reports scrubbed=false when nothing was scrubbed', () => {
|
|
219
|
+
const scrubber = new Scrubber({
|
|
220
|
+
fields: ['password'],
|
|
221
|
+
});
|
|
222
|
+
const input = { name: 'Bob', age: 30 };
|
|
223
|
+
const result = scrubber.scrub(input);
|
|
224
|
+
expect(result.scrubbed).to.be.false;
|
|
225
|
+
expect(result.scrubbedPaths).to.have.length(0);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
describe('Immutability', () => {
|
|
229
|
+
it('does not mutate original object', () => {
|
|
230
|
+
const scrubber = new Scrubber({
|
|
231
|
+
fields: ['password'],
|
|
232
|
+
});
|
|
233
|
+
const input = { user: { password: 'secret', name: 'Bob' } };
|
|
234
|
+
const original = JSON.stringify(input);
|
|
235
|
+
scrubber.scrub(input);
|
|
236
|
+
expect(JSON.stringify(input)).to.equal(original);
|
|
237
|
+
expect(input.user.password).to.equal('secret');
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe('Custom replacement text', () => {
|
|
241
|
+
it('uses custom replacement string', () => {
|
|
242
|
+
const scrubber = new Scrubber({
|
|
243
|
+
fields: ['password'],
|
|
244
|
+
replacement: '***REDACTED***',
|
|
245
|
+
});
|
|
246
|
+
const input = { password: 'secret' };
|
|
247
|
+
const { data } = scrubber.scrub(input);
|
|
248
|
+
expect(data.password).to.equal('***REDACTED***');
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
describe('Edge cases', () => {
|
|
252
|
+
it('handles null values', () => {
|
|
253
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
254
|
+
const input = { user: null };
|
|
255
|
+
const { data } = scrubber.scrub(input);
|
|
256
|
+
expect(data.user).to.be.null;
|
|
257
|
+
});
|
|
258
|
+
it('handles undefined values', () => {
|
|
259
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
260
|
+
const input = { user: undefined };
|
|
261
|
+
const { data } = scrubber.scrub(input);
|
|
262
|
+
expect(data.user).to.be.undefined;
|
|
263
|
+
});
|
|
264
|
+
it('handles empty objects', () => {
|
|
265
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
266
|
+
const input = {};
|
|
267
|
+
const { data } = scrubber.scrub(input);
|
|
268
|
+
expect(data).to.deep.equal({});
|
|
269
|
+
});
|
|
270
|
+
it('handles empty arrays', () => {
|
|
271
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
272
|
+
const input = [];
|
|
273
|
+
const { data } = scrubber.scrub(input);
|
|
274
|
+
expect(data).to.deep.equal([]);
|
|
275
|
+
});
|
|
276
|
+
it('handles primitive values', () => {
|
|
277
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
278
|
+
expect(scrubber.scrub('test').data).to.equal('test');
|
|
279
|
+
expect(scrubber.scrub(123).data).to.equal(123);
|
|
280
|
+
expect(scrubber.scrub(true).data).to.equal(true);
|
|
281
|
+
});
|
|
282
|
+
it('scrubs entire array element by index path', () => {
|
|
283
|
+
// Tests lines 76-78: scrubbing entire array element, not just a field
|
|
284
|
+
const scrubber = new Scrubber({
|
|
285
|
+
paths: ['users[0]', 'items[1]'], // Scrub specific array elements by full path
|
|
286
|
+
});
|
|
287
|
+
const input = {
|
|
288
|
+
users: [
|
|
289
|
+
{ name: 'bob', email: 'bob@example.com' }, // Should be scrubbed entirely
|
|
290
|
+
{ name: 'alice', email: 'alice@example.com' }, // Not scrubbed
|
|
291
|
+
],
|
|
292
|
+
items: [
|
|
293
|
+
{ id: 1, value: 'keep' }, // Not scrubbed
|
|
294
|
+
{ id: 2, value: 'scrub' }, // Should be scrubbed entirely
|
|
295
|
+
],
|
|
296
|
+
};
|
|
297
|
+
const { data } = scrubber.scrub(input);
|
|
298
|
+
expect(data.users?.[0]).to.equal('[SCRUBBED]');
|
|
299
|
+
expect(data.users?.[1]?.name).to.equal('alice'); // Not scrubbed
|
|
300
|
+
expect(data.items?.[0]?.value).to.equal('keep'); // Not scrubbed
|
|
301
|
+
expect(data.items?.[1]).to.equal('[SCRUBBED]'); // Entire element scrubbed
|
|
302
|
+
});
|
|
303
|
+
it('scrubs array index across all arrays', () => {
|
|
304
|
+
// Tests that index-only paths (e.g., '0') scrub that index in ALL arrays
|
|
305
|
+
const scrubber = new Scrubber({
|
|
306
|
+
paths: ['1'], // Scrub index 1 of ANY array
|
|
307
|
+
});
|
|
308
|
+
const input = {
|
|
309
|
+
users: [
|
|
310
|
+
{ name: 'bob' }, // Index 0 - not scrubbed
|
|
311
|
+
{ name: 'alice' }, // Index 1 - scrubbed
|
|
312
|
+
{ name: 'charlie' }, // Index 2 - not scrubbed
|
|
313
|
+
],
|
|
314
|
+
teams: [
|
|
315
|
+
{ id: 'team-a' }, // Index 0 - not scrubbed
|
|
316
|
+
{ id: 'team-b' }, // Index 1 - scrubbed
|
|
317
|
+
],
|
|
318
|
+
};
|
|
319
|
+
const { data } = scrubber.scrub(input);
|
|
320
|
+
expect(data.users?.[0]?.name).to.equal('bob');
|
|
321
|
+
expect(data.users?.[1]).to.equal('[SCRUBBED]'); // Scrubbed by index
|
|
322
|
+
expect(data.users?.[2]?.name).to.equal('charlie');
|
|
323
|
+
expect(data.teams?.[0]?.id).to.equal('team-a');
|
|
324
|
+
expect(data.teams?.[1]).to.equal('[SCRUBBED]'); // Scrubbed by index
|
|
325
|
+
});
|
|
326
|
+
it('handles deeply nested objects (10+ levels)', () => {
|
|
327
|
+
// Validates discovery doc requirement: "Scrubs nested objects 10+ levels deep"
|
|
328
|
+
const scrubber = new Scrubber({
|
|
329
|
+
fields: ['secret'],
|
|
330
|
+
});
|
|
331
|
+
// Build a 15-level deep object
|
|
332
|
+
const input = { level: 1 };
|
|
333
|
+
let current = input;
|
|
334
|
+
for (let i = 2; i <= 15; i++) {
|
|
335
|
+
current.nested = { level: i };
|
|
336
|
+
current = current.nested;
|
|
337
|
+
}
|
|
338
|
+
// Add secret at the deepest level
|
|
339
|
+
current.secret = 'deep-secret';
|
|
340
|
+
current.public = 'visible';
|
|
341
|
+
const { data } = scrubber.scrub(input);
|
|
342
|
+
// Navigate to the deepest level
|
|
343
|
+
let deepest = data;
|
|
344
|
+
for (let i = 1; i < 15; i++) {
|
|
345
|
+
expect(deepest.level).to.equal(i);
|
|
346
|
+
deepest = deepest.nested;
|
|
347
|
+
}
|
|
348
|
+
// Verify scrubbing worked at 15 levels deep
|
|
349
|
+
expect(deepest.level).to.equal(15);
|
|
350
|
+
expect(deepest.secret).to.equal('[SCRUBBED]');
|
|
351
|
+
expect(deepest.public).to.equal('visible');
|
|
352
|
+
});
|
|
353
|
+
it('handles circular references in deep clone fallback (arrays)', () => {
|
|
354
|
+
// Tests lines 166-172: circular reference deep clone for arrays
|
|
355
|
+
const scrubber = new Scrubber({
|
|
356
|
+
fields: ['password'],
|
|
357
|
+
});
|
|
358
|
+
// Create an object with circular references that will trigger the fallback clone
|
|
359
|
+
const parent = { name: 'parent', password: 'secret' };
|
|
360
|
+
const child1 = { name: 'child1', items: [] };
|
|
361
|
+
const child2 = { name: 'child2', password: 'hidden' };
|
|
362
|
+
// Create circular reference in an array
|
|
363
|
+
child1.items = [child2, parent]; // Array contains parent
|
|
364
|
+
parent.children = [child1]; // Parent contains array with circular ref
|
|
365
|
+
const { data } = scrubber.scrub(parent);
|
|
366
|
+
// Verify scrubbing happened
|
|
367
|
+
expect(data.password).to.equal('[SCRUBBED]');
|
|
368
|
+
expect(data.children?.[0]?.name).to.equal('child1');
|
|
369
|
+
// Verify circular reference was handled in the array
|
|
370
|
+
expect(data.children?.[0]?.items?.[1]).to.equal('[Circular Reference]');
|
|
371
|
+
});
|
|
372
|
+
it('handles arrays with circular self-reference', () => {
|
|
373
|
+
// Additional test for circular array deep cloning
|
|
374
|
+
const scrubber = new Scrubber({
|
|
375
|
+
fields: ['token'],
|
|
376
|
+
});
|
|
377
|
+
const obj = {
|
|
378
|
+
token: 'secret-token',
|
|
379
|
+
list: [{ name: 'item1' }],
|
|
380
|
+
};
|
|
381
|
+
// Array references the parent object
|
|
382
|
+
obj.list.push(obj);
|
|
383
|
+
const { data } = scrubber.scrub(obj);
|
|
384
|
+
expect(data.token).to.equal('[SCRUBBED]');
|
|
385
|
+
expect(data.list?.[0]?.name).to.equal('item1');
|
|
386
|
+
expect(data.list?.[1]).to.equal('[Circular Reference]');
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
//# sourceMappingURL=scrubber.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrubber.test.js","sourceRoot":"","sources":["../../../src/core/scrubber.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the Scrubber
|
|
3
|
+
*
|
|
4
|
+
* Defines how the scrubber should identify and replace sensitive data.
|
|
5
|
+
* Supports three complementary scrubbing strategies:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Field-based scrubbing** (`fields`): Matches field names at any depth in the object tree
|
|
8
|
+
* 2. **Path-based scrubbing** (`paths`): Matches specific dot-notation paths
|
|
9
|
+
* 3. **Pattern-based scrubbing** (`patterns`): Matches regex patterns in string content
|
|
10
|
+
*
|
|
11
|
+
* All three strategies can be used together for comprehensive data scrubbing.
|
|
12
|
+
*
|
|
13
|
+
* @example Field-based configuration
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const config: ScrubConfig = {
|
|
16
|
+
* fields: ['password', 'apiToken', /api[-_]?key/i], // Strings and regex patterns
|
|
17
|
+
* replacement: '[REDACTED]'
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Path-based configuration
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const config: ScrubConfig = {
|
|
24
|
+
* paths: [
|
|
25
|
+
* 'user.email',
|
|
26
|
+
* 'request.headers.authorization',
|
|
27
|
+
* 'items[0].password' // Array index notation
|
|
28
|
+
* ]
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example Pattern-based configuration
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const config: ScrubConfig = {
|
|
35
|
+
* patterns: [
|
|
36
|
+
* /\b\d{3}-\d{2}-\d{4}\b/g, // SSN
|
|
37
|
+
* /\d{4}-\d{4}-\d{4}-\d{4}/g, // Credit card
|
|
38
|
+
* /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}/g // Email
|
|
39
|
+
* ]
|
|
40
|
+
* };
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export interface ScrubConfig {
|
|
44
|
+
/**
|
|
45
|
+
* Field-based scrubbing: matches field names at any depth
|
|
46
|
+
*
|
|
47
|
+
* Supports both exact string matches and regular expressions for flexible matching.
|
|
48
|
+
* String matches are case-insensitive and use substring matching.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* fields: [
|
|
53
|
+
* 'password', // Matches 'password', 'Password', 'old_password', etc.
|
|
54
|
+
* 'apiToken', // Matches 'apiToken', 'api_token', etc.
|
|
55
|
+
* /api[-_]?key/i, // Regex: matches 'api_key', 'api-key', 'apikey' (case insensitive)
|
|
56
|
+
* /^secret$/ // Exact match: only 'secret', not 'my_secret'
|
|
57
|
+
* ]
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
fields?: (string | RegExp)[];
|
|
61
|
+
/**
|
|
62
|
+
* Path-based scrubbing: matches specific dot-notation paths
|
|
63
|
+
*
|
|
64
|
+
* Use dot notation to target specific fields in nested objects.
|
|
65
|
+
* Supports array index notation (e.g., `items[0].password`).
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* paths: [
|
|
70
|
+
* 'user.email', // Scrubs obj.user.email
|
|
71
|
+
* 'request.headers.authorization', // Nested path
|
|
72
|
+
* 'items[0].secret', // Array index notation
|
|
73
|
+
* 'users[0]' // Scrubs entire array element
|
|
74
|
+
* ]
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
paths?: string[];
|
|
78
|
+
/**
|
|
79
|
+
* Pattern-based scrubbing: regex patterns for content scrubbing
|
|
80
|
+
*
|
|
81
|
+
* Scans string values and replaces content matching the patterns.
|
|
82
|
+
* Use the global flag (`/pattern/g`) to replace all matches in a string.
|
|
83
|
+
*
|
|
84
|
+
* **Note**: Patterns are applied to string values only, not to field names or paths.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* patterns: [
|
|
89
|
+
* /\b\d{3}-\d{2}-\d{4}\b/g, // Social Security Number
|
|
90
|
+
* /\d{4}-\d{4}-\d{4}-\d{4}/g, // Credit Card
|
|
91
|
+
* /Bearer\s+[A-Za-z0-9._-]+/g // Bearer tokens
|
|
92
|
+
* ]
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
patterns?: RegExp[];
|
|
96
|
+
/**
|
|
97
|
+
* Replacement string for scrubbed values
|
|
98
|
+
*
|
|
99
|
+
* @default '[SCRUBBED]'
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* replacement: '[REDACTED]' // Custom replacement text
|
|
104
|
+
* replacement: '***' // Simple masking
|
|
105
|
+
* replacement: '' // Empty string (removes content)
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
replacement?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Whether to recursively scrub nested objects
|
|
111
|
+
*
|
|
112
|
+
* When `true`, the scrubber traverses the entire object tree.
|
|
113
|
+
* When `false`, only top-level fields are scrubbed.
|
|
114
|
+
*
|
|
115
|
+
* @default true
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* recursive: false // Only scrub top-level fields
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
recursive?: boolean;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Result of a scrub operation
|
|
126
|
+
*
|
|
127
|
+
* Contains the scrubbed data along with metadata about what was scrubbed.
|
|
128
|
+
*
|
|
129
|
+
* @template T - The type of the scrubbed data (same as input type)
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const scrubber = new Scrubber({ fields: ['password'] });
|
|
134
|
+
* const result = scrubber.scrub({ user: 'john', password: 'secret' });
|
|
135
|
+
*
|
|
136
|
+
* console.log(result.data); // { user: 'john', password: '[SCRUBBED]' }
|
|
137
|
+
* console.log(result.scrubbed); // true
|
|
138
|
+
* console.log(result.scrubbedPaths); // ['password']
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export interface ScrubResult<T> {
|
|
142
|
+
/**
|
|
143
|
+
* The scrubbed data with sensitive values replaced
|
|
144
|
+
*
|
|
145
|
+
* This is a deep clone of the input with scrubbed values replaced.
|
|
146
|
+
* The original input is never mutated.
|
|
147
|
+
*/
|
|
148
|
+
data: T;
|
|
149
|
+
/**
|
|
150
|
+
* Whether any scrubbing occurred
|
|
151
|
+
*
|
|
152
|
+
* `true` if at least one value was scrubbed, `false` if no sensitive data was found.
|
|
153
|
+
*
|
|
154
|
+
* Useful for logging or metrics to track scrubbing activity.
|
|
155
|
+
*/
|
|
156
|
+
scrubbed: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Array of paths that were scrubbed
|
|
159
|
+
*
|
|
160
|
+
* Contains dot-notation paths for all fields that were scrubbed.
|
|
161
|
+
* Useful for debugging, auditing, or understanding what data was redacted.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* ['password', 'user.email', 'request.headers.authorization']
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
scrubbedPaths: string[];
|
|
169
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Safety Tests for Core Scrubber
|
|
3
|
+
*
|
|
4
|
+
* These tests validate that TypeScript types are preserved correctly through scrubbing operations.
|
|
5
|
+
* They use compile-time type assertions to ensure type safety without runtime overhead.
|
|
6
|
+
*
|
|
7
|
+
* Run with: pnpm test (type-checked during pretest)
|
|
8
|
+
*/
|
|
9
|
+
export {};
|