@mossbear/eval-core 0.1.0-alpha.100

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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/adapter.d.ts +31 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +10 -0
  6. package/dist/adapter.js.map +1 -0
  7. package/dist/credential-patterns.d.ts +9 -0
  8. package/dist/credential-patterns.d.ts.map +1 -0
  9. package/dist/credential-patterns.js +9 -0
  10. package/dist/credential-patterns.js.map +1 -0
  11. package/dist/index.d.ts +12 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +11 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/redact-prose.d.ts +77 -0
  16. package/dist/redact-prose.d.ts.map +1 -0
  17. package/dist/redact-prose.js +339 -0
  18. package/dist/redact-prose.js.map +1 -0
  19. package/dist/redact-prose.test.d.ts +2 -0
  20. package/dist/redact-prose.test.d.ts.map +1 -0
  21. package/dist/redact-prose.test.js +429 -0
  22. package/dist/redact-prose.test.js.map +1 -0
  23. package/dist/redaction.d.ts +23 -0
  24. package/dist/redaction.d.ts.map +1 -0
  25. package/dist/redaction.js +23 -0
  26. package/dist/redaction.js.map +1 -0
  27. package/dist/sanitize-command.d.ts +21 -0
  28. package/dist/sanitize-command.d.ts.map +1 -0
  29. package/dist/sanitize-command.js +908 -0
  30. package/dist/sanitize-command.js.map +1 -0
  31. package/dist/sanitize-command.test.d.ts +2 -0
  32. package/dist/sanitize-command.test.d.ts.map +1 -0
  33. package/dist/sanitize-command.test.js +867 -0
  34. package/dist/sanitize-command.test.js.map +1 -0
  35. package/dist/steering-classification.d.ts +19 -0
  36. package/dist/steering-classification.d.ts.map +1 -0
  37. package/dist/steering-classification.js +55 -0
  38. package/dist/steering-classification.js.map +1 -0
  39. package/dist/strip-code-blocks.d.ts +68 -0
  40. package/dist/strip-code-blocks.d.ts.map +1 -0
  41. package/dist/strip-code-blocks.js +280 -0
  42. package/dist/strip-code-blocks.js.map +1 -0
  43. package/dist/strip-code-blocks.test.d.ts +2 -0
  44. package/dist/strip-code-blocks.test.d.ts.map +1 -0
  45. package/dist/strip-code-blocks.test.js +250 -0
  46. package/dist/strip-code-blocks.test.js.map +1 -0
  47. package/package.json +47 -0
@@ -0,0 +1,429 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { MAX_PROSE_CHARS, redactProse } from './redact-prose.js';
3
+ import { sanitizeCommand } from './sanitize-command.js';
4
+ /**
5
+ * The corpus this redactor is judged against. Each entry is a plausible line of
6
+ * assistant or user prose from a real session: what must be removed, and — just
7
+ * as load-bearing — what must survive intact.
8
+ */
9
+ describe('redactProse', () => {
10
+ describe('secrets that must not survive', () => {
11
+ it('removes a PEM private key block', () => {
12
+ const result = redactProse('Here is the key I generated:\n-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAx7Vn9kQm\nQm5kZXJ0aGVzdHJpbmc=\n-----END RSA PRIVATE KEY-----\nUse it for the deploy.' // oss-boundary-ignore — synthetic fixture, not a real key
13
+ );
14
+ expect(result.text).not.toContain('MIIEowIBAAKCAQEAx7Vn9kQm');
15
+ expect(result.text).not.toContain('BEGIN RSA PRIVATE KEY');
16
+ expect(result.text).toContain('Here is the key I generated:');
17
+ expect(result.text).toContain('Use it for the deploy.');
18
+ expect(result.counts.private_key).toBe(1);
19
+ });
20
+ // A truncated key is still a key.
21
+ it('removes an unterminated private key block', () => {
22
+ const result = redactProse('-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAA' // oss-boundary-ignore — synthetic fixture, not a real key
23
+ );
24
+ expect(result.text).not.toContain('b3BlbnNzaC1rZXktdjEAAAAA');
25
+ expect(result.counts.private_key).toBe(1);
26
+ });
27
+ it('removes credentials from a URL but keeps the host', () => {
28
+ const result = redactProse('I connected with postgres://admin:hunter2@db.example.com:5432/app and it worked.');
29
+ expect(result.text).not.toContain('hunter2');
30
+ expect(result.text).toContain('db.example.com');
31
+ expect(result.counts.url_credentials).toBe(1);
32
+ });
33
+ // `sanitizeCommand` anchors this at a shell-token boundary, which is
34
+ // exactly what misses it mid-sentence. This is the gap that made a
35
+ // separate prose redactor the load-bearing deliverable.
36
+ it('removes KEY=value embedded in a sentence', () => {
37
+ const result = redactProse('I set OPENAI_API_KEY=sk-proj-abcdefghijklmnop1234 and reran the script.');
38
+ expect(result.text).not.toContain('sk-proj-abcdefghijklmnop1234');
39
+ expect(result.text).toContain('I set OPENAI_API_KEY');
40
+ expect(result.text).toContain('and reran the script.');
41
+ });
42
+ it('removes a quoted value with spaces', () => {
43
+ const result = redactProse('The config had DB_PASSWORD = "correct horse battery"');
44
+ expect(result.text).not.toContain('correct horse battery');
45
+ expect(result.counts.assignment).toBe(1);
46
+ });
47
+ it('removes a colon-separated secret', () => {
48
+ const result = redactProse('auth token: aVeryLongOpaqueValue99');
49
+ expect(result.text).not.toContain('aVeryLongOpaqueValue99');
50
+ });
51
+ it.each([
52
+ ['Mossbear CLI', 'mossbear_aB3dEfGhIjKlMnOp'],
53
+ ['legacy auden CLI', 'auden_aB3dEfGhIjKlMnOp'],
54
+ ['OpenAI-style', 'sk-proj-QQQQwwwweeee1234RRRR'],
55
+ ['GitHub PAT', 'ghp_abcdefghijklmnopqrstuvwxyz0123'],
56
+ ['GitHub fine-grained', 'github_pat_11ABCDEFG0abcdefghij_KLMNOP'], // oss-boundary-ignore — fake token shape
57
+ ['Slack', 'xoxb-1234567890-abcdefghijkl'], // oss-boundary-ignore — fake token shape
58
+ ['AWS access key', 'AKIAIOSFODNN7EXAMPLE'], // oss-boundary-ignore — fake token shape
59
+ ['Google API key', 'AIzaSyA1234567890abcdefghijklmnopqrs'],
60
+ ])('removes a bare %s token', (_name, token) => {
61
+ const result = redactProse(`The failing call used ${token} as its credential.`);
62
+ expect(result.text).not.toContain(token);
63
+ expect(result.text).toContain('The failing call used');
64
+ expect(result.redactedCount).toBeGreaterThan(0);
65
+ });
66
+ // The product's own token, in the shapes prose actually puts it in. The
67
+ // `assignment` rule already covered `token: mossbear_…`; these three are
68
+ // the forms that had nothing to anchor on, and they are why the prefix arm
69
+ // exists. `mossbear_` keys are under `long_random_string`'s 40-character
70
+ // floor, so no other rule reaches them.
71
+ it.each([
72
+ ['a bare mention', 'use mossbear_aB3dEfGhIjKlMnOp'],
73
+ ['a sentence', 'I set my token to mossbear_aB3dEfGhIjKlMnOp and it worked'],
74
+ ['a space-separated flag', 'ran mossbear sync --token mossbear_aB3dEfGhIjKlMnOp'],
75
+ ])('removes our own CLI token in %s', (_name, prose) => {
76
+ const result = redactProse(prose);
77
+ expect(result.text).not.toContain('mossbear_aB3dEfGhIjKlMnOp');
78
+ expect(result.counts.token).toBe(1);
79
+ });
80
+ // The two redactors guard the same credential against the same upload, so
81
+ // a token one removes and the other keeps is a gap, not a difference in
82
+ // scope. This asserts they agree on the case that opened it.
83
+ it('redacts our own CLI token wherever sanitizeCommand does', () => {
84
+ const prose = 'use mossbear_aB3dEfGhIjKlMnOp';
85
+ expect(redactProse(prose).text).toBe(sanitizeCommand(prose));
86
+ });
87
+ // A pasted request header: `Authorization` is not a sensitive assignment
88
+ // key, and these values are routinely too short for the prefix and
89
+ // long-run rules, so without a rule of their own they upload verbatim.
90
+ it.each([
91
+ ['Bearer', 'Authorization: Bearer short-live-token-123', 'short-live-token-123'],
92
+ ['Basic', 'Authorization: Basic dXNlcjpwYXNz', 'dXNlcjpwYXNz'],
93
+ ])('removes an %s Authorization header credential', (_name, prose, secret) => {
94
+ const result = redactProse(prose);
95
+ expect(result.text).not.toContain(secret);
96
+ expect(result.text).toContain('Authorization');
97
+ });
98
+ // A colon-requiring pattern misses the token-as-sole-userinfo form, and
99
+ // nothing else here catches it when the token is short.
100
+ it('removes token-only URL userinfo', () => {
101
+ const result = redactProse('Connected with postgres://short-live-token@127.0.0.1/db');
102
+ expect(result.text).not.toContain('short-live-token');
103
+ expect(result.text).toContain('127.0.0.1');
104
+ });
105
+ // Stopping at the first inner quote leaves the tail of the password in
106
+ // place, which is worse than not matching at all — it looks redacted.
107
+ it('consumes escaped quotes inside a quoted value', () => {
108
+ const result = redactProse('DB_PASSWORD="correct horse \\"battery staple"');
109
+ expect(result.text).not.toContain('battery staple');
110
+ expect(result.text).toBe('DB_PASSWORD=[redacted]');
111
+ });
112
+ // `+` and `/` are base64 characters but not word characters, so a leading
113
+ // one leaves `\b` nothing to match and the run one short of the floor.
114
+ it('removes a base64 run beginning with a non-word character', () => {
115
+ const secret = '/123456789012345678901234567890123456789';
116
+ const result = redactProse(`The blob was ${secret} in the header.`);
117
+ expect(result.text).not.toContain(secret);
118
+ expect(result.counts.long_random_string).toBe(1);
119
+ });
120
+ it('removes email addresses', () => {
121
+ const result = redactProse('Ping alex.doe+work@example.co.uk about the migration.');
122
+ expect(result.text).not.toContain('alex.doe+work@example.co.uk');
123
+ expect(result.text).toContain('about the migration.');
124
+ expect(result.counts.email).toBe(1);
125
+ });
126
+ it('removes a long opaque base64/hex run', () => {
127
+ const digest = 'a3f5c9e17b2d4869fa0c5e3d7b91240affe6c8d251b7093e';
128
+ const result = redactProse(`The session id was ${digest} in the logs.`);
129
+ expect(result.text).not.toContain(digest);
130
+ expect(result.counts.long_random_string).toBe(1);
131
+ });
132
+ it('removes every secret when a message carries several', () => {
133
+ const result = redactProse('Mailed ops@example.com the key ghp_abcdefghijklmnopqrstuvwxyz0123 and set API_KEY=topsecret123');
134
+ expect(result.text).not.toContain('ops@example.com');
135
+ expect(result.text).not.toContain('ghp_abcdefghijklmnopqrstuvwxyz0123');
136
+ expect(result.text).not.toContain('topsecret123');
137
+ expect(result.redactedCount).toBeGreaterThanOrEqual(3);
138
+ });
139
+ });
140
+ /**
141
+ * The other half of the contract. Prose scrubbed into nonsense is useless to
142
+ * a grader and alarming to a reader, so over-redaction is a defect too.
143
+ */
144
+ describe('ordinary text that must not be mangled', () => {
145
+ it.each([
146
+ "I'm going to refactor the sync queue because the retry logic double-counts.",
147
+ 'The test failed at src/lib/runs/format.ts:42 with a TypeError.',
148
+ 'Renaming getUserById to fetchUserById across 14 call sites; the answer: 42.',
149
+ 'Run `bun run test` first — it takes about 18 seconds on this machine.',
150
+ 'The verdict vocabulary is aligned | unguided | misaligned, never anything else.',
151
+ 'See https://example.com/docs/getting-started for the setup steps.',
152
+ // The prefix arm must not turn the product's own name into a secret:
153
+ // `mossbear` is a word this corpus is full of, and only `mossbear_`
154
+ // followed by a key-length run is a credential.
155
+ 'Run mossbear sync after the hook writes, then check the feed.',
156
+ 'The mossbear_ prefix is what API_KEY_PREFIX expands to.',
157
+ ])('leaves %s untouched', (prose) => {
158
+ const result = redactProse(prose);
159
+ expect(result.text).toBe(prose);
160
+ expect(result.redactedCount).toBe(0);
161
+ });
162
+ // The floor on the loosest pattern is what protects ordinary language:
163
+ // English words, paths and identifiers do not reach 40 unbroken characters.
164
+ it('does not redact a long ordinary sentence as a random string', () => {
165
+ const prose = 'The implementation of the deterministic detector counts distinct runs rather than rows.';
166
+ const result = redactProse(prose);
167
+ expect(result.text).toBe(prose);
168
+ });
169
+ // As an arbitrary substring, SECRET matches `secretary` and TOKEN matches
170
+ // `tokenization`. These are ordinary prose, not credential assignments.
171
+ it.each([
172
+ ['secretary: Alice', 'Alice'],
173
+ ['tokenization: complete', 'complete'],
174
+ ['The password reset flow: works now', 'works now'],
175
+ ])('keeps %s, whose key only contains a sensitive word', (prose, value) => {
176
+ expect(redactProse(prose).text).toContain(value);
177
+ });
178
+ // Length alone is not a random-string signal. Redacting a long identifier
179
+ // removes the exact implementation detail a grader needs.
180
+ it.each([
181
+ 'createAuthenticatedDashboardRequestContext',
182
+ 'useRunGuideVerdictLabelsWithFallbackResolution',
183
+ ])('keeps the long ordinary identifier %s', (identifier) => {
184
+ const prose = `The call to ${identifier} failed.`;
185
+ expect(redactProse(prose).text).toBe(prose);
186
+ });
187
+ it('keeps a non-sensitive assignment', () => {
188
+ const prose = 'I set NODE_ENV=production and the build shrank by 40%.';
189
+ const result = redactProse(prose);
190
+ expect(result.text).toBe(prose);
191
+ });
192
+ });
193
+ describe('length capping', () => {
194
+ it('caps and marks a message past the limit', () => {
195
+ const long = 'word '.repeat(MAX_PROSE_CHARS);
196
+ const result = redactProse(long);
197
+ expect(result.wasTruncated).toBe(true);
198
+ expect(result.text).toContain('[truncated]');
199
+ expect(result.text.length).toBeLessThan(MAX_PROSE_CHARS + 30);
200
+ });
201
+ it('leaves a message inside the limit alone', () => {
202
+ const result = redactProse('A short explanation of the change.');
203
+ expect(result.wasTruncated).toBe(false);
204
+ expect(result.text).not.toContain('[truncated]');
205
+ });
206
+ // The output cap is not a bound on the work: without a scan bound every
207
+ // pattern scans the whole untrusted message first, and the assignment
208
+ // matcher backtracks badly on adversarial input.
209
+ it('bounds the work on a hostile input rather than only the output', () => {
210
+ const hostile = `${'SECRET'.repeat(200_000)} tail`;
211
+ const started = performance.now();
212
+ const result = redactProse(hostile);
213
+ const elapsedMs = performance.now() - started;
214
+ expect(elapsedMs).toBeLessThan(2000);
215
+ expect(result.wasTruncated).toBe(true);
216
+ expect(result.text.length).toBeLessThan(MAX_PROSE_CHARS + 30);
217
+ });
218
+ // The cap is the backstop for whatever the patterns miss, so it has to
219
+ // apply after redaction rather than instead of it.
220
+ it('still redacts before truncating', () => {
221
+ const result = redactProse(`ghp_abcdefghijklmnopqrstuvwxyz0123 ${'padding '.repeat(MAX_PROSE_CHARS)}`);
222
+ expect(result.text).not.toContain('ghp_abcdefghijklmnopqrstuvwxyz0123');
223
+ expect(result.wasTruncated).toBe(true);
224
+ });
225
+ });
226
+ describe('the report', () => {
227
+ it('counts each class separately', () => {
228
+ const result = redactProse('Contact a@example.com and b@example.com; the token is ghp_abcdefghijklmnopqrstuvwxyz0123');
229
+ expect(result.counts.email).toBe(2);
230
+ expect(result.counts.token).toBe(1);
231
+ expect(result.redactedCount).toBe(3);
232
+ });
233
+ it('omits classes that redacted nothing', () => {
234
+ const result = redactProse('Ping ops@example.com when the deploy lands.');
235
+ expect(result.counts.email).toBe(1);
236
+ expect(result.counts.private_key).toBeUndefined();
237
+ expect(result.counts.token).toBeUndefined();
238
+ });
239
+ it('reports nothing redacted for clean prose', () => {
240
+ const result = redactProse('Nothing sensitive here at all.');
241
+ expect(result.counts).toEqual({});
242
+ expect(result.redactedCount).toBe(0);
243
+ });
244
+ it('treats empty, null, and undefined as empty prose', () => {
245
+ for (const input of ['', null, undefined]) {
246
+ const result = redactProse(input);
247
+ expect(result.text).toBe('');
248
+ expect(result.redactedCount).toBe(0);
249
+ expect(result.wasTruncated).toBe(false);
250
+ }
251
+ });
252
+ });
253
+ // A stateful `g` regex silently skipping the first match of the next message
254
+ // is exactly the failure a redactor must not have.
255
+ it('redacts identically on repeated calls', () => {
256
+ const prose = 'The key ghp_abcdefghijklmnopqrstuvwxyz0123 leaked into the log.';
257
+ const first = redactProse(prose);
258
+ const second = redactProse(prose);
259
+ const third = redactProse(prose);
260
+ expect(second.text).toBe(first.text);
261
+ expect(third.text).toBe(first.text);
262
+ expect(second.counts).toEqual(first.counts);
263
+ });
264
+ });
265
+ describe('credential disclosure regressions', () => {
266
+ it.each([
267
+ 'You can pass --token to the sync command.',
268
+ 'It takes --password or prompts you.',
269
+ 'I recommend --client-secret for the CI job.',
270
+ ])('preserves prose explaining credential options: %s', (input) => {
271
+ expect(redactProse(input).text).toBe(input);
272
+ });
273
+ it.each(['password', '"password"', "'password'"])('counts one YAML block credential under %s once', (key) => {
274
+ const result = redactProse(`${key}: |\n fixture-secret\n fixture-tail\nname: reader`);
275
+ expect(result.text).not.toContain('fixture');
276
+ expect(result.text).toContain('name: reader');
277
+ expect(result.counts.assignment).toBe(1);
278
+ expect(result.redactedCount).toBe(1);
279
+ });
280
+ it('counts a bounded nested JSON replacement', () => {
281
+ const nested = Array.from({ length: 25 }).reduce((value) => ({ child: value }), 'fixture-secret');
282
+ const result = redactProse(JSON.stringify({ payload: JSON.stringify(nested) }));
283
+ expect(result.text).not.toContain('fixture-secret');
284
+ expect(result.counts.assignment).toBe(1);
285
+ expect(result.redactedCount).toBe(1);
286
+ });
287
+ it('redacts quoted JSON keys in transcript prose, including escaped keys', () => {
288
+ for (const input of [
289
+ 'The response was {"password":"fixture-json-secret","ok":true}.',
290
+ 'The response was {"clientSecret":"fixture-json-secret"}.',
291
+ String.raw `{"\u0070assword":"fixture-json-secret"}`,
292
+ ]) {
293
+ expect(redactProse(input).text).not.toContain('fixture-json-secret');
294
+ }
295
+ });
296
+ it('redacts multiline and concatenated quoted credential values completely', () => {
297
+ for (const input of [
298
+ 'password="fixture-first\nfixture-tail" after',
299
+ "SECRET='first'fixture-tail after",
300
+ 'password="fixture-first\nfixture-tail',
301
+ ]) {
302
+ const output = redactProse(input).text;
303
+ expect(output).not.toContain('fixture-first');
304
+ expect(output).not.toContain('fixture-tail');
305
+ }
306
+ });
307
+ it('redacts session cookies pasted into prose', () => {
308
+ for (const name of ['Cookie', 'Set-Cookie'])
309
+ expect(redactProse(`${name}: session=fixture-cookie; Path=/`).text).not.toContain('fixture-cookie');
310
+ });
311
+ });
312
+ describe('review evidence-preservation regressions', () => {
313
+ it('preserves prose following an ordinary apostrophe', () => {
314
+ const input = "I reset the password: it's stored in the vault now, so the deploy can retry safely.";
315
+ expect(redactProse(input).text).toContain('stored in the vault now, so the deploy can retry safely.');
316
+ });
317
+ it('does not treat discussion of a cookie header as a credential', () => {
318
+ const input = 'The API expects a Cookie: header with the session token. Retry after rotating it.';
319
+ expect(redactProse(input).text).toBe(input);
320
+ });
321
+ it('preserves prose after a cookie value while removing every cookie pair', () => {
322
+ const text = redactProse('Cookie: session=fixture-cookie; csrf=fixture-csrf Retry after rotating it.').text;
323
+ expect(text).not.toContain('fixture-cookie');
324
+ expect(text).not.toContain('fixture-csrf');
325
+ expect(text).toContain('Retry after rotating it.');
326
+ });
327
+ it.each(['clientSecret', 'client_secret', 'PRIVATE_KEY', 'authorization'])('redacts unquoted %s keys', (key) => {
328
+ expect(redactProse(`${key}: fixture-secret here`).text).not.toContain('fixture-secret');
329
+ });
330
+ });
331
+ describe('credential syntax in uploaded narration', () => {
332
+ it.each(['--auth.token', '--spring.datasource.password'])('retains redaction for dotted credential options: %s', (flag) => {
333
+ const report = redactProse(`I ran deploy ${flag} "fixture-secret" --verbose.`);
334
+ expect(report.text).not.toContain('fixture-secret');
335
+ expect(report.text).toContain('--verbose.');
336
+ });
337
+ it.each([
338
+ "I ran deploy --password=$'fixture secret' retried.",
339
+ String.raw `I ran deploy --password=$'fixture\' secret' retried.`,
340
+ "I ran deploy --password=$'fixture'credential retried.",
341
+ String.raw `I set password=$'fixture\nsecret' retried.`,
342
+ ])('redacts complete attached ANSI-C credential values: %s', (input) => {
343
+ const report = redactProse(input);
344
+ expect(report.text).not.toContain('fixture');
345
+ expect(report.text).not.toContain(' secret');
346
+ expect(report.text).not.toContain('credential');
347
+ expect(report.text).toContain('retried.');
348
+ });
349
+ it.each(['|', '>-', '|2+'])('redacts YAML sequence credentials with %s while preserving siblings', (marker) => {
350
+ const report = redactProse(`accounts:\n - password: ${marker}\n fixture-secret\n fixture-tail\n name: reader\n - name: second`);
351
+ expect(report.text).not.toContain('fixture');
352
+ expect(report.text).toContain(' name: reader\n - name: second');
353
+ expect(report.redactedCount).toBe(1);
354
+ });
355
+ it.each([
356
+ "{'password': 'first' 'fixture-tail', 'action': 'retry'}",
357
+ '{"password": "first" "fixture-tail", "action": "retry"}',
358
+ "{'password': 'first'\n'fixture-tail', 'action': 'retry'}",
359
+ ])('redacts adjacent Python credential strings in %s', (input) => {
360
+ const report = redactProse(input);
361
+ expect(report.text).not.toContain('first');
362
+ expect(report.text).not.toContain('fixture-tail');
363
+ expect(report.text).toContain('retry');
364
+ });
365
+ it('preserves a quoted YAML sibling after a quoted credential', () => {
366
+ expect(redactProse("'password': 'fixture-secret'\n'action': 'retry'").text).toContain("'action': 'retry'");
367
+ });
368
+ it.each(['--tokenizer', '--secretary'])('preserves the unrelated quoted option %s', (flag) => {
369
+ const input = `I ran encode ${flag} "cl100k base" and compared the output.`;
370
+ expect(redactProse(input).text).toBe(input);
371
+ });
372
+ it.each([
373
+ "I ran deploy --password $'fixture credential' --verbose.",
374
+ String.raw `I ran deploy --password $'fixture\' credential' --verbose.`,
375
+ String.raw `I ran deploy --password $'fixture\ncredential' --verbose.`,
376
+ "I ran deploy --password $'fixture'credential --verbose.",
377
+ ])('redacts ANSI-C quoted command credentials: %s', (input) => {
378
+ const report = redactProse(input);
379
+ expect(report.text).not.toContain('fixture');
380
+ expect(report.text).not.toContain('credential');
381
+ expect(report.text).toContain('--verbose.');
382
+ });
383
+ it.each(['--password', '--api-key', '--token', '--client-secret'])('redacts prose mentioning the %s command option', (flag) => {
384
+ const report = redactProse(`I ran deploy ${flag} "fixture secret with spaces" --verbose yesterday.`);
385
+ expect(report.text).not.toContain('fixture');
386
+ expect(report.text).not.toContain('with spaces');
387
+ expect(report.text).toContain('--verbose yesterday.');
388
+ expect(report.counts.assignment).toBeGreaterThan(0);
389
+ });
390
+ it.each(['|', '|-', '|+', '>', '>2-'])('redacts complete YAML credentials in %s block scalars', (marker) => {
391
+ const report = redactProse(`config:\n password: ${marker}\n fixture secret\n second secret line\n retries: 3\nNext step`);
392
+ expect(report.text).not.toContain('fixture');
393
+ expect(report.text).not.toContain('second secret line');
394
+ expect(report.text).toContain(' retries: 3\nNext step');
395
+ expect(report.counts.assignment).toBeGreaterThan(0);
396
+ });
397
+ it('redacts recursively serialized JSON inside prose while retaining benign fields', () => {
398
+ let value = JSON.stringify({
399
+ password: 'fixture private credential',
400
+ action: 'retry',
401
+ });
402
+ for (let depth = 0; depth < 4; depth += 1) {
403
+ value = JSON.stringify({ payload: value, count: 2 });
404
+ const report = redactProse(`I sent ${value} then retried.`);
405
+ expect(report.text).not.toContain('fixture');
406
+ expect(report.text).not.toContain('private credential');
407
+ expect(report.text).toContain('retry');
408
+ expect(report.text).toContain('then retried.');
409
+ }
410
+ });
411
+ it.each([
412
+ "{'password': 'fixture secret', 'action': 'retry'}",
413
+ '{\'api_key\': "fixture secret"}',
414
+ ])('redacts single-quoted mapping keys in %s', (input) => {
415
+ const report = redactProse(input);
416
+ expect(report.text).not.toContain('fixture');
417
+ expect(report.text).not.toContain(' secret');
418
+ expect(report.counts.assignment).toBeGreaterThan(0);
419
+ });
420
+ it('preserves ordinary quoted narration and non-secret YAML blocks', () => {
421
+ for (const text of [
422
+ 'I said "retry the migration".',
423
+ 'notes: |\n keep this explanation\nretries: 3',
424
+ ]) {
425
+ expect(redactProse(text).text).toBe(text);
426
+ }
427
+ });
428
+ });
429
+ //# sourceMappingURL=redact-prose.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact-prose.test.js","sourceRoot":"","sources":["../src/redact-prose.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Facts shared by this package's two redactors.
3
+ *
4
+ * `sanitizeCommand` (shell command text) and `redactProse` (transcript prose)
5
+ * are deliberately separate scanners — see the header of `./redact-prose.ts`
6
+ * for why one cannot be built out of the other. But a few of the things they
7
+ * match are the *same fact* stated twice, and a hardening applied to one copy
8
+ * while the other is forgotten is a credential on the wire. Those live here.
9
+ */
10
+ /** Marker substituted for every redacted span, in both redactors. */
11
+ export declare const REDACTED = "[redacted]";
12
+ /**
13
+ * Matches a whole private-key block, including an unterminated one — a
14
+ * truncated key is still a key.
15
+ *
16
+ * Exported as a **source string** rather than a shared `RegExp`: a `g`-flagged
17
+ * regex object carries `lastIndex` between calls, and a single instance shared
18
+ * across modules is exactly the stateful-regex hazard `redactProse` guards
19
+ * against when it counts matches. Each call site builds its own instance from
20
+ * this source, so no state can leak between them.
21
+ */
22
+ export declare const PRIVATE_KEY_BLOCK_SOURCE: string;
23
+ //# sourceMappingURL=redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,qEAAqE;AACrE,eAAO,MAAM,QAAQ,eAAe,CAAA;AAEpC;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,QAA6F,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Facts shared by this package's two redactors.
3
+ *
4
+ * `sanitizeCommand` (shell command text) and `redactProse` (transcript prose)
5
+ * are deliberately separate scanners — see the header of `./redact-prose.ts`
6
+ * for why one cannot be built out of the other. But a few of the things they
7
+ * match are the *same fact* stated twice, and a hardening applied to one copy
8
+ * while the other is forgotten is a credential on the wire. Those live here.
9
+ */
10
+ /** Marker substituted for every redacted span, in both redactors. */
11
+ export const REDACTED = '[redacted]';
12
+ /**
13
+ * Matches a whole private-key block, including an unterminated one — a
14
+ * truncated key is still a key.
15
+ *
16
+ * Exported as a **source string** rather than a shared `RegExp`: a `g`-flagged
17
+ * regex object carries `lastIndex` between calls, and a single instance shared
18
+ * across modules is exactly the stateful-regex hazard `redactProse` guards
19
+ * against when it counts matches. Each call site builds its own instance from
20
+ * this source, so no state can leak between them.
21
+ */
22
+ export const PRIVATE_KEY_BLOCK_SOURCE = String.raw `-----BEGIN[A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END[A-Z ]*PRIVATE KEY-----|$)`;
23
+ //# sourceMappingURL=redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.js","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,qEAAqE;AACrE,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAA;AAEpC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAAA,gFAAgF,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Secret redaction and length-capping for shell command text.
3
+ *
4
+ * Command text can embed secrets or whole file bodies (heredocs, inline env
5
+ * vars). The CLI runs logged commands through this before creating an action
6
+ * summary. Recognized credential syntax is removed; arbitrary shell/tool
7
+ * programs remain an open language, so pattern scanning cannot prove that
8
+ * every surviving argument is credential-free.
9
+ *
10
+ * Lives in eval-core rather than the CLI because grading is what consumes the
11
+ * result: this is the boundary that decides what a grader may ever see of a
12
+ * command.
13
+ */
14
+ /**
15
+ * Redact common secret shapes from a shell command and cap its length so
16
+ * command text never carries credentials or bulk file content off-box.
17
+ *
18
+ * Pure function — no I/O.
19
+ */
20
+ export declare function sanitizeCommand(command: string): string;
21
+ //# sourceMappingURL=sanitize-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-command.d.ts","sourceRoot":"","sources":["../src/sanitize-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAq7BH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQvD"}