@tangle-network/agent-eval 0.193.0 → 0.193.2
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/CHANGELOG.md +22 -2
- package/dist/analyst/index.d.ts +2 -2
- package/dist/analyst/index.js +4 -4
- package/dist/{benchmark-command-DVhUPU7H.js → benchmark-command-N5r3GXMP.js} +8 -8
- package/dist/{benchmark-command-DVhUPU7H.js.map → benchmark-command-N5r3GXMP.js.map} +1 -1
- package/dist/benchmarks/index.js +3 -3
- package/dist/campaign/index.js +4 -4
- package/dist/{campaign-DdE6S80e.js → campaign-DnL0S4XL.js} +6 -6
- package/dist/{campaign-DdE6S80e.js.map → campaign-DnL0S4XL.js.map} +1 -1
- package/dist/{chat-client-B_ItsSBw.js → chat-client-CJORSG_J.js} +2 -2
- package/dist/{chat-client-B_ItsSBw.js.map → chat-client-CJORSG_J.js.map} +1 -1
- package/dist/{chat-json-call-CXHBvUz8.js → chat-json-call-DnlDjpco.js} +2 -2
- package/dist/{chat-json-call-CXHBvUz8.js.map → chat-json-call-DnlDjpco.js.map} +1 -1
- package/dist/cli.js +3 -3
- package/dist/contract/index.js +6 -6
- package/dist/{define-agent-eval-DkPbnJEY.js → define-agent-eval-qxAPjMSL.js} +3 -3
- package/dist/{define-agent-eval-DkPbnJEY.js.map → define-agent-eval-qxAPjMSL.js.map} +1 -1
- package/dist/diagnosis/index.d.ts +1 -1
- package/dist/diagnosis/index.d.ts.map +1 -1
- package/dist/diagnosis/index.js +11 -5
- package/dist/diagnosis/index.js.map +1 -1
- package/dist/{dspy-rlm-engine-BX34vPVY.js → dspy-rlm-engine-k_QdEBZo.js} +2 -2
- package/dist/{dspy-rlm-engine-BX34vPVY.js.map → dspy-rlm-engine-k_QdEBZo.js.map} +1 -1
- package/dist/{eval-campaign-CwsBn0Gm.js → eval-campaign-CXT2WYUe.js} +2 -2
- package/dist/{eval-campaign-CwsBn0Gm.js.map → eval-campaign-CXT2WYUe.js.map} +1 -1
- package/dist/{external-optimizer-process-D-Sab4v3.js → external-optimizer-process-_YIECYJ7.js} +2 -2
- package/dist/{external-optimizer-process-D-Sab4v3.js.map → external-optimizer-process-_YIECYJ7.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-kbqC-iWf.js → external-optimizer-subprocess-BrghTvEp.js} +2 -2
- package/dist/{external-optimizer-subprocess-kbqC-iWf.js.map → external-optimizer-subprocess-BrghTvEp.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +56 -21
- package/dist/index.js.map +1 -1
- package/dist/{llm-client-KYQBh9C8.js → llm-client-c_bKHTXz.js} +2 -2
- package/dist/{llm-client-KYQBh9C8.js.map → llm-client-c_bKHTXz.js.map} +1 -1
- package/dist/{llm-judge-ChbWfeWl.js → llm-judge-Cififl_V.js} +4 -4
- package/dist/{llm-judge-ChbWfeWl.js.map → llm-judge-Cififl_V.js.map} +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{otel-spans-DS7t1t1J.js → otel-spans-CQmSxtcS.js} +2 -2
- package/dist/{otel-spans-DS7t1t1J.js.map → otel-spans-CQmSxtcS.js.map} +1 -1
- package/dist/pipelines/index.d.ts +1 -1
- package/dist/{produced-state-BqeIaIp2.js → produced-state-B2AhDRnq.js} +3 -3
- package/dist/{produced-state-BqeIaIp2.js.map → produced-state-B2AhDRnq.js.map} +1 -1
- package/dist/{raw-provider-sink-DYh4Bszw.js → raw-provider-sink-CXuOhLvT.js} +2 -2
- package/dist/{raw-provider-sink-DYh4Bszw.js.map → raw-provider-sink-CXuOhLvT.js.map} +1 -1
- package/dist/{redact-CopuMxll.d.ts → redact-Cveoq6fJ.d.ts} +2 -2
- package/dist/{redact-CopuMxll.d.ts.map → redact-Cveoq6fJ.d.ts.map} +1 -1
- package/dist/{redact-B7rt9Zot.js → redact-Dk1ZdJEm.js} +59 -26
- package/dist/redact-Dk1ZdJEm.js.map +1 -0
- package/dist/rl.js +1 -1
- package/dist/{semantic-concept-judge-Bg-560H0.js → semantic-concept-judge-Bh5lvKGg.js} +4 -4
- package/dist/{semantic-concept-judge-Bg-560H0.js.map → semantic-concept-judge-Bh5lvKGg.js.map} +1 -1
- package/dist/{server-DtetGGoA.js → server-D56r1lhp.js} +2 -2
- package/dist/{server-DtetGGoA.js.map → server-D56r1lhp.js.map} +1 -1
- package/dist/{skillopt-optimization-method-DXQdaBjx.js → skillopt-optimization-method-C6DbFKnw.js} +5 -5
- package/dist/{skillopt-optimization-method-DXQdaBjx.js.map → skillopt-optimization-method-C6DbFKnw.js.map} +1 -1
- package/dist/{spans-BWtjk_9c.d.ts → spans-D9_ehFuk.d.ts} +2 -2
- package/dist/{spans-BWtjk_9c.d.ts.map → spans-D9_ehFuk.d.ts.map} +1 -1
- package/dist/{store-tool-spans-BcC_5ef-.js → store-tool-spans-BaGakFc2.js} +2 -2
- package/dist/{store-tool-spans-BcC_5ef-.js.map → store-tool-spans-BaGakFc2.js.map} +1 -1
- package/dist/{task-failure-attributes-CEqEfuIY.js → task-failure-attributes-DngaLdE4.js} +4 -3
- package/dist/task-failure-attributes-DngaLdE4.js.map +1 -0
- package/dist/traces.d.ts +1 -1
- package/dist/traces.js +4 -4
- package/dist/wire/index.js +1 -1
- package/package.json +2 -2
- package/dist/redact-B7rt9Zot.js.map +0 -1
- package/dist/task-failure-attributes-CEqEfuIY.js.map +0 -1
|
@@ -45,7 +45,7 @@ const REDACTION_PROFILES = [
|
|
|
45
45
|
* redaction behavior (saved optimizer inputs, per-span redaction stamps) keys
|
|
46
46
|
* on it, so bump it whenever a detector, key list, cap or marker changes.
|
|
47
47
|
*/
|
|
48
|
-
const REDACTION_VERSION = "2.
|
|
48
|
+
const REDACTION_VERSION = "2.4.0";
|
|
49
49
|
const KIB = 1024;
|
|
50
50
|
const PROFILE_RULES = {
|
|
51
51
|
default: {
|
|
@@ -293,6 +293,17 @@ function classifyKey(key) {
|
|
|
293
293
|
/**
|
|
294
294
|
* High-confidence credential shapes. A hit replaces the whole string. Each
|
|
295
295
|
* pattern is written without the `g` flag so `test` stays stateless.
|
|
296
|
+
*
|
|
297
|
+
* The provider-branded prefixes below (`sk-ant-`, `AIza`, `ghp_`, `xoxb-`,
|
|
298
|
+
* `AKIA`, `hubcap_`, `eyJ`…) have no leading `\b`. A `\b` word-boundary
|
|
299
|
+
* assertion does not fire between two word characters, so it silently passed
|
|
300
|
+
* a real token when something else glued a word character directly in front
|
|
301
|
+
* of it — a compound identifier like `env.GITHUB_TOKEN_ghp_<token>` (a `_`
|
|
302
|
+
* before `ghp_`) or `BACKUP_AKIA<key>` (a `_` before `AKIA`). These prefixes
|
|
303
|
+
* are distinctive enough on their own, so scanning without that boundary
|
|
304
|
+
* catches the same real credential wherever it is glued, at the cost of no
|
|
305
|
+
* meaningful new false positives (`scripts/redaction-corpus.json` covers
|
|
306
|
+
* both).
|
|
296
307
|
*/
|
|
297
308
|
const CREDENTIAL_DETECTORS = [
|
|
298
309
|
{
|
|
@@ -301,7 +312,7 @@ const CREDENTIAL_DETECTORS = [
|
|
|
301
312
|
},
|
|
302
313
|
{
|
|
303
314
|
id: "jwt",
|
|
304
|
-
pattern:
|
|
315
|
+
pattern: /eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/
|
|
305
316
|
},
|
|
306
317
|
{
|
|
307
318
|
id: "bearer",
|
|
@@ -313,39 +324,39 @@ const CREDENTIAL_DETECTORS = [
|
|
|
313
324
|
},
|
|
314
325
|
{
|
|
315
326
|
id: "anthropic-key",
|
|
316
|
-
pattern:
|
|
327
|
+
pattern: /sk-ant-[A-Za-z0-9_-]{16,}/
|
|
317
328
|
},
|
|
318
329
|
{
|
|
319
330
|
id: "provider-key",
|
|
320
|
-
pattern:
|
|
331
|
+
pattern: /sk-(?:proj-|tan-)?[A-Za-z0-9_-]{16,}/
|
|
321
332
|
},
|
|
322
333
|
{
|
|
323
334
|
id: "stripe-key",
|
|
324
|
-
pattern:
|
|
335
|
+
pattern: /(?:sk|rk)_(?:live|test)_[A-Za-z0-9_]{10,}/
|
|
325
336
|
},
|
|
326
337
|
{
|
|
327
338
|
id: "google-api-key",
|
|
328
|
-
pattern:
|
|
339
|
+
pattern: /AIza[0-9A-Za-z_-]{20,}/
|
|
329
340
|
},
|
|
330
341
|
{
|
|
331
342
|
id: "github-token",
|
|
332
|
-
pattern:
|
|
343
|
+
pattern: /(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})/
|
|
333
344
|
},
|
|
334
345
|
{
|
|
335
346
|
id: "slack-token",
|
|
336
|
-
pattern:
|
|
347
|
+
pattern: /xox[abeoprs]-[A-Za-z0-9-]{10,}/
|
|
337
348
|
},
|
|
338
349
|
{
|
|
339
350
|
id: "aws-access-key",
|
|
340
|
-
pattern:
|
|
351
|
+
pattern: /(?:AKIA|ASIA)[A-Z0-9]{16}\b/
|
|
341
352
|
},
|
|
342
353
|
{
|
|
343
354
|
id: "tangle-capability",
|
|
344
|
-
pattern:
|
|
355
|
+
pattern: /(?:hubcap_|hct_)[A-Za-z0-9_=-]{8,}/
|
|
345
356
|
},
|
|
346
357
|
{
|
|
347
358
|
id: "url-credentials",
|
|
348
|
-
pattern: /\b[a-z][a-z0-9+.-]
|
|
359
|
+
pattern: /\b[a-z][a-z0-9+.-]{0,31}:\/\/[^\s/:@]{1,512}:[^\s/@]{1,512}@/i
|
|
349
360
|
},
|
|
350
361
|
{
|
|
351
362
|
id: "url-secret-param",
|
|
@@ -353,7 +364,7 @@ const CREDENTIAL_DETECTORS = [
|
|
|
353
364
|
},
|
|
354
365
|
{
|
|
355
366
|
id: "secret-assignment",
|
|
356
|
-
pattern: /(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|secret|token|password|passwd|passphrase|credentials?)["']?[ \t]*[:=][ \t]*["']?(?!encrypted:)(?![$`<[{(%])(?=[^\s"'`,;&|]
|
|
367
|
+
pattern: /(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|secret|token|password|passwd|passphrase|credentials?)["']?[ \t]*[:=][ \t]*["']?(?!encrypted:)(?![$`<[{(%])(?=[^\s"'`,;&|]{0,512}[0-9])(?=[^\s"'`,;&|]{0,512}[A-Za-z])[^\s"'`,;&|]{12,512}/i
|
|
357
368
|
},
|
|
358
369
|
{
|
|
359
370
|
id: "json-secret",
|
|
@@ -365,27 +376,27 @@ const CREDENTIAL_DETECTORS = [
|
|
|
365
376
|
},
|
|
366
377
|
{
|
|
367
378
|
id: "huggingface-token",
|
|
368
|
-
pattern:
|
|
379
|
+
pattern: /hf_[A-Za-z0-9]{20,}/
|
|
369
380
|
},
|
|
370
381
|
{
|
|
371
382
|
id: "npm-token",
|
|
372
|
-
pattern:
|
|
383
|
+
pattern: /npm_[A-Za-z0-9]{20,}/
|
|
373
384
|
},
|
|
374
385
|
{
|
|
375
386
|
id: "gitlab-token",
|
|
376
|
-
pattern:
|
|
387
|
+
pattern: /glpat-[A-Za-z0-9_-]{16,}/
|
|
377
388
|
},
|
|
378
389
|
{
|
|
379
390
|
id: "groq-key",
|
|
380
|
-
pattern:
|
|
391
|
+
pattern: /gsk_[A-Za-z0-9]{20,}/
|
|
381
392
|
},
|
|
382
393
|
{
|
|
383
394
|
id: "xai-key",
|
|
384
|
-
pattern:
|
|
395
|
+
pattern: /xai-[A-Za-z0-9]{16,}/
|
|
385
396
|
},
|
|
386
397
|
{
|
|
387
398
|
id: "bare-sk-key",
|
|
388
|
-
pattern:
|
|
399
|
+
pattern: /sk_[A-Za-z0-9]{32,}\b/
|
|
389
400
|
},
|
|
390
401
|
{
|
|
391
402
|
id: "cookie-header",
|
|
@@ -512,12 +523,22 @@ function knownSecretForms(values) {
|
|
|
512
523
|
return [...forms].sort((left, right) => right.length - left.length);
|
|
513
524
|
}
|
|
514
525
|
const BASE64_TEXT = /^[A-Za-z0-9+/_-]+={0,2}$/;
|
|
526
|
+
const EMBEDDED_BASE64 = /[A-Za-z0-9+/]{16,4096}={0,2}/g;
|
|
515
527
|
function containsKnownSecret(text, forms) {
|
|
516
528
|
if (forms.length === 0) return false;
|
|
517
529
|
if (forms.some((form) => text.includes(form))) return true;
|
|
518
|
-
if (text.length
|
|
519
|
-
|
|
520
|
-
|
|
530
|
+
if (text.length >= 8 && BASE64_TEXT.test(text)) {
|
|
531
|
+
const decoded = Buffer.from(text, text.includes("-") || text.includes("_") ? "base64url" : "base64").toString("utf8");
|
|
532
|
+
if (forms.some((form) => decoded.includes(form))) return true;
|
|
533
|
+
}
|
|
534
|
+
for (const match of text.matchAll(EMBEDDED_BASE64)) {
|
|
535
|
+
if (match[0] === text) continue;
|
|
536
|
+
try {
|
|
537
|
+
const decoded = Buffer.from(match[0], "base64").toString("utf8");
|
|
538
|
+
if (forms.some((form) => decoded.includes(form))) return true;
|
|
539
|
+
} catch {}
|
|
540
|
+
}
|
|
541
|
+
return false;
|
|
521
542
|
}
|
|
522
543
|
/** The detector that marks `text` as a credential: a known secret first, then the value shapes. */
|
|
523
544
|
function credentialIn(text, knownSecrets) {
|
|
@@ -630,19 +651,23 @@ function redactStringAt(text, path, state) {
|
|
|
630
651
|
record(state, path, "media", "media", "redacted");
|
|
631
652
|
return marker("media");
|
|
632
653
|
}
|
|
633
|
-
const
|
|
654
|
+
const boundLen = Math.min(output.length, state.maxStringBytes);
|
|
655
|
+
let scanTarget = output.slice(0, boundLen);
|
|
656
|
+
const tail = output.slice(boundLen);
|
|
657
|
+
const credential = credentialIn(scanTarget, state.knownSecrets);
|
|
634
658
|
if (credential) {
|
|
635
659
|
record(state, path, "credential", credential, "redacted");
|
|
636
660
|
return marker(credential);
|
|
637
661
|
}
|
|
638
662
|
for (const detector of PERSONAL_DATA_DETECTORS) {
|
|
639
|
-
if (detector.requires && !
|
|
640
|
-
|
|
663
|
+
if (detector.requires && !scanTarget.includes(detector.requires)) continue;
|
|
664
|
+
scanTarget = scanTarget.replace(detector.pattern, (match) => {
|
|
641
665
|
if (detector.accept && !detector.accept(match)) return match;
|
|
642
666
|
record(state, path, "personal-data", detector.id, "redacted");
|
|
643
667
|
return marker(detector.id);
|
|
644
668
|
});
|
|
645
669
|
}
|
|
670
|
+
output = scanTarget + tail;
|
|
646
671
|
const truncated = truncateUtf8(output, state.maxStringBytes);
|
|
647
672
|
if (truncated === void 0) return output;
|
|
648
673
|
record(state, path, "raw-content", "size-cap", "truncated");
|
|
@@ -702,10 +727,15 @@ function walk(value, path, depth, state) {
|
|
|
702
727
|
for (const [key, item] of Object.entries(value)) {
|
|
703
728
|
let outKey = key;
|
|
704
729
|
const keyCredential = credentialIn(key, state.knownSecrets);
|
|
730
|
+
const keyPersonalData = keyCredential ? void 0 : detectPersonalData(key)[0];
|
|
705
731
|
if (keyCredential) {
|
|
706
732
|
renamed += 1;
|
|
707
733
|
outKey = `${marker(keyCredential)}#${renamed}`;
|
|
708
734
|
record(state, pointer(path, outKey), "credential", keyCredential, "redacted");
|
|
735
|
+
} else if (keyPersonalData) {
|
|
736
|
+
renamed += 1;
|
|
737
|
+
outKey = `${marker(keyPersonalData)}#${renamed}`;
|
|
738
|
+
record(state, pointer(path, outKey), "personal-data", keyPersonalData, "redacted");
|
|
709
739
|
}
|
|
710
740
|
out[outKey] = redactKeyed(key, item, pointer(path, outKey), depth, state);
|
|
711
741
|
}
|
|
@@ -859,8 +889,11 @@ function scan(value, path, depth, state) {
|
|
|
859
889
|
}
|
|
860
890
|
for (const [key, item] of Object.entries(value)) {
|
|
861
891
|
const keyCredential = credentialIn(key, state.knownSecrets);
|
|
862
|
-
const
|
|
892
|
+
const keyPersonalData = keyCredential ? void 0 : detectPersonalData(key)[0];
|
|
893
|
+
const keyDetector = keyCredential ?? keyPersonalData;
|
|
894
|
+
const segment = keyDetector ? marker(keyDetector) : key;
|
|
863
895
|
if (keyCredential) flag(state, pointer(path, segment), "credential", keyCredential);
|
|
896
|
+
else if (keyPersonalData) flag(state, pointer(path, segment), "personal-data", keyPersonalData);
|
|
864
897
|
scanKeyed(key, item, pointer(path, segment), depth, state);
|
|
865
898
|
}
|
|
866
899
|
} finally {
|
|
@@ -941,4 +974,4 @@ function redactForShare(value, options = {}) {
|
|
|
941
974
|
//#endregion
|
|
942
975
|
export { combineVerdicts as a, emptyRedactionReport as c, redactForShare as d, redactText as f, classifyKey as i, normalizeKey as l, REDACTION_VERSION as n, detectCredential as o, shareAllowed as p, assessShareSafety as r, detectPersonalData as s, REDACTION_PROFILES as t, redact as u };
|
|
943
976
|
|
|
944
|
-
//# sourceMappingURL=redact-
|
|
977
|
+
//# sourceMappingURL=redact-Dk1ZdJEm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-Dk1ZdJEm.js","names":[],"sources":["../src/trace/redact.ts"],"sourcesContent":["/**\n * The redaction core: the one place that decides what must not leave a\n * process or a machine. Every trace writer, exporter, uploader and share path\n * calls it.\n *\n * Three profiles, each a superset of the one before:\n * - `default` removes credentials, found by key name and by value shape, and\n * personal data (email addresses, card numbers, SSNs, phone numbers).\n * Content is kept. Strings are capped at 1 MiB.\n * - `share` also removes phone, IP and postal-address fields, replaces\n * account, user, tenant, session and request identifiers with pseudonyms\n * that stay consistent within one call, and caps strings at 64 KiB.\n * - `strict` also removes prompt, completion, message, tool payload and other\n * raw-content fields and embedded media, and caps strings at 4 KiB.\n *\n * A string that holds a credential is replaced whole with\n * `[REDACTED:<detector>]`. Replacing only the matched span can leave part of a\n * secret behind when a pattern's boundary is wrong. Personal data inside prose\n * is replaced in place, so the rest of the text stays readable.\n *\n * `assessShareSafety` reads a value without changing it and returns SAFE,\n * SAFE_WITH_WARNINGS, UNSAFE or UNKNOWN. UNKNOWN means the scanner could not\n * read part of the value (a cycle, binary data, nesting past the depth limit);\n * it is never reported as safe. `redactForShare` redacts and then assesses the\n * redacted output, so a detector gap shows up as UNSAFE instead of a leak.\n *\n * Reports and findings carry paths, categories and detector ids, never the\n * values they matched.\n *\n * The key classifier and the credential detector list are adapted from\n * agent-inspect (MIT, commit 3c3cbeda). `scripts/redaction-corpus.json` holds\n * the must-flag and must-not-flag cases, including the copied agent-inspect\n * safety corpus with its MIT notice; `pnpm redaction:corpus` runs this module\n * over every case.\n */\n\nimport { createHmac, randomBytes } from 'node:crypto'\n\nexport type RedactionProfile = 'default' | 'share' | 'strict'\n\nexport const REDACTION_PROFILES: readonly RedactionProfile[] = ['default', 'share', 'strict']\n\n/** What a finding is about. `media` is embedded binary content (a `data:` URI) no text detector can read. */\nexport type SafetyCategory = 'credential' | 'personal-data' | 'identifier' | 'raw-content' | 'media'\n\n/**\n * Version of the detector set and profile rules. Stored work that depends on\n * redaction behavior (saved optimizer inputs, per-span redaction stamps) keys\n * on it, so bump it whenever a detector, key list, cap or marker changes.\n */\nexport const REDACTION_VERSION = '2.4.0'\n\nexport interface RedactionFinding {\n /** JSON Pointer (RFC 6901) to the value or key that was changed. */\n path: string\n category: SafetyCategory\n detector: string\n action: 'redacted' | 'pseudonymized' | 'truncated'\n}\n\nexport interface RedactionReport {\n version: string\n profile: RedactionProfile\n /** Values and keys replaced, pseudonymized or truncated. */\n redactionCount: number\n byDetector: Record<string, number>\n truncatedCount: number\n findings: RedactionFinding[]\n}\n\nexport interface RedactOptions {\n /** Default `default`. */\n profile?: RedactionProfile\n /** Lower the profile's per-string cap. A value above the profile cap is ignored. */\n maxStringBytes?: number\n /**\n * Exact values the caller knows are secret (an API key the run was given, a\n * password from the environment), whatever shape they have. Each occurrence\n * in a string, as written or base64, base64url or URL-encoded, becomes\n * `[REDACTED:known-secret]` and the text around it is kept. A key that\n * contains one, and a whole-string base64 payload that holds one at any byte\n * offset, is replaced whole.\n */\n knownSecrets?: readonly string[]\n /** Add this call's findings to an existing report instead of a new one. */\n report?: RedactionReport\n}\n\nexport interface AssessOptions {\n /** Default `default`. */\n profile?: RedactionProfile\n /** As in `RedactOptions`: any surviving occurrence makes the verdict UNSAFE. */\n knownSecrets?: readonly string[]\n}\n\nexport type ShareSafetyStatus = 'SAFE' | 'SAFE_WITH_WARNINGS' | 'UNSAFE' | 'UNKNOWN'\n\nexport interface ShareSafetyFinding {\n category: SafetyCategory\n detector: string\n severity: 'error' | 'warning'\n count: number\n /** Up to five JSON Pointers where the detector fired. */\n paths: string[]\n}\n\nexport interface ShareSafetyVerdict {\n status: ShareSafetyStatus\n profile: RedactionProfile\n findings: ShareSafetyFinding[]\n /** Parts the scanner could not read, as `<path>: <reason>`. Any entry makes the status UNKNOWN. */\n unreadable: string[]\n}\n\n// ── Profiles ─────────────────────────────────────────────────────────────\n\ninterface ProfileRules {\n maxStringBytes: number\n /** Key categories whose values are removed or pseudonymized. */\n redactKeys: ReadonlySet<'share-personal' | 'identifier' | 'raw-content'>\n redactMedia: boolean\n severity: Record<SafetyCategory, 'error' | 'warning' | undefined>\n}\n\nconst KIB = 1024\n\nconst PROFILE_RULES: Record<RedactionProfile, ProfileRules> = {\n default: {\n maxStringBytes: 1024 * KIB,\n redactKeys: new Set(),\n redactMedia: false,\n severity: {\n credential: 'error',\n 'personal-data': 'warning',\n identifier: undefined,\n 'raw-content': 'warning',\n media: 'warning',\n },\n },\n share: {\n maxStringBytes: 64 * KIB,\n redactKeys: new Set(['share-personal', 'identifier']),\n redactMedia: false,\n severity: {\n credential: 'error',\n 'personal-data': 'error',\n identifier: 'warning',\n 'raw-content': 'warning',\n media: 'warning',\n },\n },\n strict: {\n maxStringBytes: 4 * KIB,\n redactKeys: new Set(['share-personal', 'identifier', 'raw-content']),\n redactMedia: true,\n severity: {\n credential: 'error',\n 'personal-data': 'error',\n identifier: 'warning',\n 'raw-content': 'error',\n media: 'error',\n },\n },\n}\n\n// ── Key classifier ───────────────────────────────────────────────────────\n\n/**\n * Canonical snake_case form of a field name, so camelCase, kebab-case, dotted\n * and snake_case spellings match one list: `userPassword`, `user-password` and\n * `user.password` all become `user_password`.\n */\nexport function normalizeKey(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n}\n\n/** Counts, limits and model vocabulary that contain the word \"token\" but are not credentials. */\nconst NON_CREDENTIAL_TOKEN_KEYS: ReadonlySet<string> = new Set([\n 'tokens',\n 'max_tokens',\n 'min_tokens',\n 'ls_max_tokens',\n 'token_count',\n 'token_limit',\n 'token_budget',\n 'input_tokens',\n 'output_tokens',\n 'total_tokens',\n 'cached_tokens',\n 'prompt_tokens',\n 'completion_tokens',\n 'reasoning_tokens',\n 'bos_token',\n 'eos_token',\n 'pad_token',\n 'unk_token',\n 'sep_token',\n 'cls_token',\n 'mask_token',\n 'stop_token',\n // Pagination cursors are opaque but not credentials.\n 'page_token',\n 'next_page_token',\n 'prev_page_token',\n 'next_token',\n 'continuation_token',\n 'cursor_token',\n 'sync_token',\n])\n\nconst CREDENTIAL_KEYS = [\n 'authorization',\n 'auth',\n 'cookie',\n 'api_key',\n 'apikey',\n 'api_token',\n 'access_key',\n 'secret_key',\n 'private_key',\n 'signing_key',\n 'encryption_key',\n 'master_key',\n 'session_key',\n 'client_secret',\n 'secret',\n 'password',\n 'passwd',\n 'passphrase',\n 'credential',\n 'credentials',\n 'bearer',\n 'dsn',\n 'database_url',\n 'connection_string',\n 'pat',\n] as const\n\n/** Email fields are personal data in every profile. */\nconst EMAIL_KEYS = ['email', 'email_address'] as const\n\n/** Personal-data fields removed by the share and strict profiles. */\nconst SHARE_PERSONAL_KEYS = [\n 'phone',\n 'phone_number',\n 'mobile',\n 'ip',\n 'ip_address',\n 'remote_addr',\n 'street_address',\n 'postal_address',\n 'home_address',\n 'billing_address',\n 'shipping_address',\n 'mailing_address',\n 'date_of_birth',\n 'dob',\n 'ssn',\n] as const\n\n/** Identifiers pseudonymized by the share and strict profiles. */\nconst IDENTIFIER_KEYS = [\n 'user_id',\n 'user_uuid',\n 'account_id',\n 'account_uuid',\n 'customer_id',\n 'tenant_id',\n 'org_id',\n 'organization_id',\n 'organisation_id',\n 'team_id',\n 'enduser_id',\n 'actor_id',\n 'principal_id',\n 'member_id',\n 'session_id',\n 'request_id',\n 'correlation_id',\n 'device_id',\n 'installation_id',\n] as const\n\n/** Fields that carry prompts, model output, tool payloads or other free text. Removed by `strict`. */\nconst RAW_CONTENT_KEYS = [\n 'prompt',\n 'prompts',\n 'system_prompt',\n 'completion',\n 'input',\n 'output',\n 'message',\n 'messages',\n 'content',\n 'text',\n 'thinking',\n 'reasoning',\n 'transcript',\n 'context',\n 'document',\n 'documents',\n 'chunk',\n 'chunks',\n 'retrieval',\n 'query',\n 'args',\n 'arguments',\n 'result',\n 'body',\n 'command',\n 'full_command',\n 'input_value',\n 'output_value',\n 'instructions',\n 'system_instructions',\n 'stdout',\n 'stderr',\n 'stacktrace',\n 'status_description',\n 'input_preview',\n 'output_preview',\n 'current_task',\n 'user_input',\n 'request_text',\n] as const\n\n/**\n * A key matches a list entry exactly or as a suffix (`openai_api_key`,\n * `db_password`, `tool_output`). Prefix compounds (`secret_name`,\n * `password_min_length`, `auth_type`, `content_type`) do not match: they name\n * or describe a value rather than hold it, and flagging them would make the\n * share verdict refuse ordinary traces. Value detectors still catch a\n * credential-shaped value under any key.\n */\nfunction matchesKeyList(normalized: string, keys: readonly string[]): boolean {\n for (const key of keys) {\n if (normalized === key || normalized.endsWith(`_${key}`)) return true\n }\n return false\n}\n\nfunction isTokenCredentialKey(normalized: string): boolean {\n if (NON_CREDENTIAL_TOKEN_KEYS.has(normalized)) return false\n if (normalized === 'token') return true\n // access_token and refreshToken are credentials; max_tokens and input_tokens are counts.\n if (normalized.endsWith('tokens')) return false\n return normalized.endsWith('token')\n}\n\ntype KeyClass = 'credential' | 'email' | 'share-personal' | 'identifier' | 'raw-content'\n\n/** Trace keys repeat on every span, so classifications are cached. */\nconst keyClassCache = new Map<string, KeyClass | null>()\n\nfunction classifyKeyName(key: string): KeyClass | undefined {\n const cached = keyClassCache.get(key)\n if (cached !== undefined) return cached ?? undefined\n const kind = classifyNormalizedKey(normalizeKey(key))\n if (keyClassCache.size >= 10_000) keyClassCache.clear()\n keyClassCache.set(key, kind ?? null)\n return kind\n}\n\nfunction classifyNormalizedKey(normalized: string): KeyClass | undefined {\n if (!normalized || NON_CREDENTIAL_TOKEN_KEYS.has(normalized)) return undefined\n if (isTokenCredentialKey(normalized)) return 'credential'\n if (matchesKeyList(normalized, CREDENTIAL_KEYS)) return 'credential'\n if (matchesKeyList(normalized, EMAIL_KEYS)) return 'email'\n if (matchesKeyList(normalized, SHARE_PERSONAL_KEYS)) return 'share-personal'\n if (matchesKeyList(normalized, IDENTIFIER_KEYS)) return 'identifier'\n if (matchesKeyList(normalized, RAW_CONTENT_KEYS)) return 'raw-content'\n return undefined\n}\n\n/**\n * The safety category a field name puts its value in, or undefined for an\n * ordinary field. Token counts and model limits (`inputTokens`, `max_tokens`,\n * `token_count`) and names such as `author` are not credentials.\n */\nexport function classifyKey(key: string): SafetyCategory | undefined {\n const kind = classifyKeyName(key)\n if (kind === undefined) return undefined\n if (kind === 'credential') return 'credential'\n if (kind === 'identifier') return 'identifier'\n if (kind === 'raw-content') return 'raw-content'\n return 'personal-data'\n}\n\n// ── Value detectors ──────────────────────────────────────────────────────\n\ninterface ValueDetector {\n id: string\n pattern: RegExp\n}\n\n/**\n * High-confidence credential shapes. A hit replaces the whole string. Each\n * pattern is written without the `g` flag so `test` stays stateless.\n *\n * The provider-branded prefixes below (`sk-ant-`, `AIza`, `ghp_`, `xoxb-`,\n * `AKIA`, `hubcap_`, `eyJ`…) have no leading `\\b`. A `\\b` word-boundary\n * assertion does not fire between two word characters, so it silently passed\n * a real token when something else glued a word character directly in front\n * of it — a compound identifier like `env.GITHUB_TOKEN_ghp_<token>` (a `_`\n * before `ghp_`) or `BACKUP_AKIA<key>` (a `_` before `AKIA`). These prefixes\n * are distinctive enough on their own, so scanning without that boundary\n * catches the same real credential wherever it is glued, at the cost of no\n * meaningful new false positives (`scripts/redaction-corpus.json` covers\n * both).\n */\nconst CREDENTIAL_DETECTORS: readonly ValueDetector[] = [\n { id: 'private-key', pattern: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/ },\n { id: 'jwt', pattern: /eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}/ },\n { id: 'bearer', pattern: /\\bbearer\\s+[A-Za-z0-9._~+/=-]{12,}/i },\n {\n id: 'authorization-header',\n pattern: /^\\s*(?:basic|digest|apikey)\\s+[A-Za-z0-9._~+/=:-]{8,}\\s*$/i,\n },\n { id: 'anthropic-key', pattern: /sk-ant-[A-Za-z0-9_-]{16,}/ },\n { id: 'provider-key', pattern: /sk-(?:proj-|tan-)?[A-Za-z0-9_-]{16,}/ },\n { id: 'stripe-key', pattern: /(?:sk|rk)_(?:live|test)_[A-Za-z0-9_]{10,}/ },\n { id: 'google-api-key', pattern: /AIza[0-9A-Za-z_-]{20,}/ },\n { id: 'github-token', pattern: /(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})/ },\n { id: 'slack-token', pattern: /xox[abeoprs]-[A-Za-z0-9-]{10,}/ },\n { id: 'aws-access-key', pattern: /(?:AKIA|ASIA)[A-Z0-9]{16}\\b/ },\n { id: 'tangle-capability', pattern: /(?:hubcap_|hct_)[A-Za-z0-9_=-]{8,}/ },\n {\n // Scheme, userinfo user and password each bounded (32/512/512 chars): the\n // unbounded `*`/`+` here made `detectCredential` catastrophically slow on\n // adversarial text with no `://` at all — 256 KiB of `\"a.\"` took ~59s,\n // measured before this fix (scratchpad/rv/before.ts). A real URL's scheme\n // and userinfo are always far under these bounds.\n id: 'url-credentials',\n pattern: /\\b[a-z][a-z0-9+.-]{0,31}:\\/\\/[^\\s/:@]{1,512}:[^\\s/@]{1,512}@/i,\n },\n {\n id: 'url-secret-param',\n pattern:\n /[?&](?:access_token|api_key|apikey|auth|token|secret|password|sig|signature|x-amz-signature|x-goog-signature)=[^&\\s\"'#)]{8,}/i,\n },\n {\n // `GH_TOKEN=…`, `--api-key=…`, `\"client_secret\": \"…\"`, `password: …` in free\n // text. The value must mix letters and digits and be at least 12\n // characters, so prose (`token: string`), variable references (`$TOKEN`)\n // and dotenvx ciphertext (`encrypted:…`) pass. The pattern starts at the\n // key word itself, with no identifier prefix, so it scans in linear time.\n // The two mixed-content lookaheads and the value itself are bounded to\n // 512 chars: unbounded, `'token='` repeated took ~20s at 256 KiB and\n // `'password:x'` repeated took ~12s at 256 KiB (measured before this fix,\n // scratchpad/rv/before.ts). A real credential value is always far under\n // 512 chars.\n id: 'secret-assignment',\n pattern:\n /(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|secret|token|password|passwd|passphrase|credentials?)[\"']?[ \\t]*[:=][ \\t]*[\"']?(?!encrypted:)(?![$`<[{(%])(?=[^\\s\"'`,;&|]{0,512}[0-9])(?=[^\\s\"'`,;&|]{0,512}[A-Za-z])[^\\s\"'`,;&|]{12,512}/i,\n },\n {\n // `{\"password\": \"hunter2\"}` or `'client_secret': '…'` inside serialized\n // JSON, YAML or a log line. A quoted credential field name followed by a\n // quoted value holds a secret whatever the value's shape or length. Bare\n // `\"token\"` is left out: model logprob output uses it for text tokens.\n // Placeholders (`[REDACTED…]`, `$VAR`, `{env:VAR}`, `***`, `<value>`) and\n // prose with two or more spaces (a field description) do not match.\n id: 'json-secret',\n pattern:\n /[\"'][A-Za-z0-9_.-]{0,40}?(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|secret|password|passwd|passphrase|credentials?|(?:access|refresh|id|auth|session|bearer|api|github|gh|slack|npm)[_-]?token)[\"'][ \\t]*:[ \\t]*[\"'](?!\\[REDACTED|[$*{<])(?![^\"'\\r\\n]* [^\"'\\r\\n]* )[^\"'\\r\\n]{3,}[\"']/i,\n },\n {\n // `DB_PASSWORD=CorrectHorseBatteryStaple`, `PGPASSWORD=postgres`: unlike\n // `secret-assignment` above, the all-upper-case env-var name ending in a\n // credential word is itself the signal, so a letters-only or short real\n // password still matches (no digit-mixing or 12-char minimum). Requires\n // the name to be immediately followed by `=`, so `MAX_TOKENS=16` and\n // `TOKEN_EXPIRY=…` (the word isn't the end of the name) do not match.\n id: 'env-secret-assignment',\n pattern:\n /\\b[A-Z][A-Z0-9_]*?(?:PASSWORD|PASSWD|SECRET|PASSPHRASE|APIKEY|API_KEY|TOKEN|CREDENTIALS?)[ \\t]*=[ \\t]*(?!\\$|<|\\*|\\{|%|encrypted:)[^\\s\"'`,;&|]{4,}/,\n },\n // Bare-key shapes not covered above. Each requires a distinctive prefix so\n // it does not fire on ordinary identifiers — same reasoning as the\n // provider-branded block above, and the same leading-`\\b` bug: a token\n // glued to preceding text by a digit or underscore (`1ghp_…`, `_sk_live_…`)\n // is invisible to an anchored detector.\n { id: 'huggingface-token', pattern: /hf_[A-Za-z0-9]{20,}/ },\n { id: 'npm-token', pattern: /npm_[A-Za-z0-9]{20,}/ },\n { id: 'gitlab-token', pattern: /glpat-[A-Za-z0-9_-]{16,}/ },\n { id: 'groq-key', pattern: /gsk_[A-Za-z0-9]{20,}/ },\n { id: 'xai-key', pattern: /xai-[A-Za-z0-9]{16,}/ },\n // ElevenLabs and similar bare `sk_<hex>` shapes — underscore, unlike the\n // hyphenated `sk-…` `provider-key` pattern above, so the two never overlap.\n { id: 'bare-sk-key', pattern: /sk_[A-Za-z0-9]{32,}\\b/ },\n {\n // `Cookie: sessionid=…; csrftoken=…` in free text or a captured header.\n id: 'cookie-header',\n pattern: /\\bcookie\\s*:\\s*[A-Za-z0-9_-]+=[^;\\r\\n]{3,}(?:;\\s*[A-Za-z0-9_-]+=[^;\\r\\n]{3,})*/i,\n },\n]\n\n/** Personal-data shapes, replaced in place so the surrounding text survives. */\nconst PERSONAL_DATA_DETECTORS: readonly (ValueDetector & {\n /** A substring the text must contain before the pattern runs. */\n requires?: string\n accept?: (match: string) => boolean\n})[] = [\n {\n id: 'email',\n requires: '@',\n pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g,\n accept: isEmailAddress,\n },\n {\n // Card numbers: a card-network prefix and a valid Luhn digit, written\n // unbroken (13-19 digits) or in printed groups (4-4-4-4, 4-4-4-4-3, Amex\n // 4-6-5). A word character or hyphen on either side rejects the match, so\n // digits inside UUIDs, dated file names and hyphenated ids never match.\n id: 'card-number',\n pattern:\n /(?<![\\w-])(?:\\d{13,19}|\\d{4}([ -])\\d{4}\\1\\d{4}\\1\\d{4}(?:\\1\\d{3})?|\\d{4}([ -])\\d{6}\\2\\d{5})(?![\\w-])/g,\n accept: (match) => {\n const digits = match.replace(/[ -]/g, '')\n return CARD_PREFIX.test(digits) && luhnValid(digits)\n },\n },\n { id: 'ssn', pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g },\n {\n // Separators are required: a bare ten-digit run is usually an epoch second or an id.\n id: 'phone',\n pattern: /(?:\\+1[-.\\s]?)?(?:\\(\\d{3}\\)\\s?|\\b\\d{3}[-.\\s])\\d{3}[-.\\s]\\d{4}\\b/g,\n },\n]\n\n/** Visa, Mastercard, Amex, Diners, JCB, Discover and UnionPay issuer prefixes. */\nconst CARD_PREFIX = /^(?:4|5[1-5]|2[2-7]|3[04-9]|6(?:011|4[4-9]|5|2))/\n\n/**\n * Top-level domains that are file extensions: `icon@2x.png`, `worker@3.service`\n * and `notes@AGENTS.md` are not addresses.\n */\nconst NON_EMAIL_TLDS: ReadonlySet<string> = new Set([\n 'md',\n 'mdx',\n 'txt',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'toml',\n 'lock',\n 'ts',\n 'tsx',\n 'js',\n 'jsx',\n 'mjs',\n 'cjs',\n 'py',\n 'rs',\n 'go',\n 'sh',\n 'css',\n 'html',\n 'svg',\n 'png',\n 'jpg',\n 'jpeg',\n 'gif',\n 'webp',\n 'service',\n 'socket',\n 'timer',\n 'mount',\n 'target',\n])\n\nfunction isEmailAddress(match: string): boolean {\n // `git@github.com:org/repo` is an SSH remote, not a person.\n if (match.toLowerCase().startsWith('git@')) return false\n const tld = match.slice(match.lastIndexOf('.') + 1).toLowerCase()\n return !NON_EMAIL_TLDS.has(tld)\n}\n\nfunction luhnValid(digits: string): boolean {\n if (/^(\\d)\\1+$/.test(digits)) return false\n let sum = 0\n let double = false\n for (let index = digits.length - 1; index >= 0; index -= 1) {\n let digit = digits.charCodeAt(index) - 48\n if (double) {\n digit *= 2\n if (digit > 9) digit -= 9\n }\n sum += digit\n double = !double\n }\n return sum % 10 === 0\n}\n\n/** The first credential detector that matches, or undefined. */\nexport function detectCredential(text: string): string | undefined {\n for (const detector of CREDENTIAL_DETECTORS) {\n if (detector.pattern.test(text)) return detector.id\n }\n return undefined\n}\n\n/** Personal-data detector ids that match somewhere in `text`. */\nexport function detectPersonalData(text: string): string[] {\n const hits: string[] = []\n for (const detector of PERSONAL_DATA_DETECTORS) {\n if (detector.requires && !text.includes(detector.requires)) continue\n detector.pattern.lastIndex = 0\n for (const match of text.matchAll(detector.pattern)) {\n if (!detector.accept || detector.accept(match[0])) {\n hits.push(detector.id)\n break\n }\n }\n }\n return hits\n}\n\n/**\n * Every form in which a known secret can appear in a trace: as written,\n * base64, base64url and URL-encoded. Values shorter than 4 characters are\n * ignored; they would match ordinary text.\n */\nfunction knownSecretForms(values: readonly string[] | undefined): string[] {\n const forms = new Set<string>()\n for (const value of values ?? []) {\n if (value.length < 4) continue\n const bytes = Buffer.from(value, 'utf8')\n forms.add(value)\n forms.add(bytes.toString('base64'))\n forms.add(bytes.toString('base64url'))\n forms.add(encodeURIComponent(value))\n }\n // Longest first, so a secret that contains another is reported as itself.\n return [...forms].sort((left, right) => right.length - left.length)\n}\n\nconst BASE64_TEXT = /^[A-Za-z0-9+/_-]+={0,2}$/\n\n// A base64 blob embedded in larger text — `Authorization: Basic <base64>` is\n// the common case — can hold a known secret without the WHOLE string being\n// base64. Bounded to 4096 chars per candidate: this scans in linear time (the\n// sum of candidate lengths is at most `text.length`), so no ReDoS risk.\nconst EMBEDDED_BASE64 = /[A-Za-z0-9+/]{16,4096}={0,2}/g\n\nfunction containsKnownSecret(text: string, forms: readonly string[]): boolean {\n if (forms.length === 0) return false\n if (forms.some((form) => text.includes(form))) return true\n // A whole-string base64 payload can hold a secret at any byte offset.\n if (text.length >= 8 && BASE64_TEXT.test(text)) {\n const decoded = Buffer.from(\n text,\n text.includes('-') || text.includes('_') ? 'base64url' : 'base64',\n ).toString('utf8')\n if (forms.some((form) => decoded.includes(form))) return true\n }\n // `Basic <base64(user:key)>` jointly encodes the userinfo, so the secret's\n // OWN base64 form (added to `forms` above) is generally not a substring of\n // it — 3-byte base64 group alignment shifts with whatever precedes the\n // secret in the original bytes. Decode any embedded base64-looking run and\n // check its plaintext directly instead of relying on aligned forms.\n for (const match of text.matchAll(EMBEDDED_BASE64)) {\n if (match[0] === text) continue // already checked above\n try {\n const decoded = Buffer.from(match[0], 'base64').toString('utf8')\n if (forms.some((form) => decoded.includes(form))) return true\n } catch {\n // Not valid base64 (e.g. wrong padding) — not a candidate.\n }\n }\n return false\n}\n\n/** The detector that marks `text` as a credential: a known secret first, then the value shapes. */\nfunction credentialIn(text: string, knownSecrets: readonly string[]): string | undefined {\n return containsKnownSecret(text, knownSecrets) ? 'known-secret' : detectCredential(text)\n}\n\nconst MARKER_PREFIX = '[REDACTED:'\n\nfunction marker(detector: string): string {\n return `${MARKER_PREFIX}${detector}]`\n}\n\n/**\n * Placeholders other tools write for a removed value. A credential field that\n * holds one of these is already redacted and is not flagged again.\n */\nconst REDACTED_PLACEHOLDER =\n /^(?:\\[(?:REDACTED|redacted)(?::[^\\]]*)?\\]|\\[ID:[0-9a-f]{12}\\]|\\*{3,}|<redacted>|«redacted»|\\[HASH:[0-9a-f]{8,}\\])$/\n\nfunction isPlaceholder(value: string): boolean {\n return value === '' || REDACTED_PLACEHOLDER.test(value)\n}\n\n// The whole string must be the data URI — `$` at the end, not just a `^`\n// prefix check. A prefix-only check let `data:text/plain;base64,…\\n` PLUS\n// arbitrary trailing text through as unread \"media\", when the trailing text\n// (or, for text/json mimes, the payload itself once decoded) is exactly the\n// kind of prose a credential or personal-data detector should see.\nconst DATA_URI = /^data:([\\w.+-]+\\/[\\w.+-]+)(?:;[\\w.+-]+=[\\w.+-]+)*;base64,([A-Za-z0-9+/=\\s]*)$/i\n\n/** A data: URI's mime type and base64 payload, only when the whole string is the URI. */\nfunction matchDataUri(text: string): { mime: string; payload: string } | undefined {\n const m = DATA_URI.exec(text)\n if (!m) return undefined\n return { mime: (m[1] ?? '').toLowerCase(), payload: m[2] ?? '' }\n}\n\n/** Decodes a data: URI's base64 payload to text, or undefined if it is not valid base64. */\nfunction decodeDataUriPayload(payload: string): string | undefined {\n const cleaned = payload.replace(/\\s+/g, '')\n if (cleaned.length === 0) return ''\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleaned) || cleaned.length % 4 !== 0) return undefined\n try {\n return Buffer.from(cleaned, 'base64').toString('utf8')\n } catch {\n return undefined\n }\n}\n\nconst READABLE_IMAGE_MIME = /^image\\//\n/** Mimes whose payload is text a detector can read once decoded. */\nconst DECODABLE_TEXT_MIME = /^text\\/|^application\\/json$/\n\n/** Whether a decoded data: URI payload holds a credential or personal data,\n * by key name (for application/json) or by value shape (for any text). */\nfunction decodedPayloadIsUnsafe(\n decoded: string,\n mime: string,\n knownSecrets: readonly string[],\n): boolean {\n if (mime === 'application/json') {\n try {\n return jsonValueIsUnsafe(JSON.parse(decoded), knownSecrets)\n } catch {\n // Not actually valid JSON despite the mime type — fall through to plain text.\n }\n }\n if (credentialIn(decoded, knownSecrets)) return true\n return detectPersonalData(decoded).length > 0\n}\n\nfunction jsonValueIsUnsafe(value: unknown, knownSecrets: readonly string[]): boolean {\n if (value === null || value === undefined) return false\n if (typeof value === 'string')\n return credentialIn(value, knownSecrets) !== undefined || detectPersonalData(value).length > 0\n if (typeof value !== 'object') return false\n if (Array.isArray(value)) return value.some((item) => jsonValueIsUnsafe(item, knownSecrets))\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n const category = classifyKey(key)\n if (category === 'credential') return true\n if (category === 'personal-data' && (typeof item === 'string' || typeof item === 'number'))\n return true\n if (jsonValueIsUnsafe(item, knownSecrets)) return true\n }\n return false\n}\n\n// ── Redaction ────────────────────────────────────────────────────────────\n\nconst MAX_DEPTH = 64\n\ninterface WalkState {\n rules: ProfileRules\n maxStringBytes: number\n knownSecrets: string[]\n report: RedactionReport\n /** Created on first use: most calls pseudonymize nothing. */\n pseudonymKey?: Buffer\n seen: WeakSet<object>\n}\n\nfunction record(\n state: WalkState,\n path: string,\n category: SafetyCategory,\n detector: string,\n action: RedactionFinding['action'],\n): void {\n const report = state.report\n if (action === 'truncated') report.truncatedCount += 1\n report.redactionCount += 1\n report.byDetector[detector] = (report.byDetector[detector] ?? 0) + 1\n report.findings.push({ path, category, detector, action })\n}\n\nfunction pointer(parent: string, key: string | number): string {\n return `${parent}/${String(key).replace(/~/g, '~0').replace(/\\//g, '~1')}`\n}\n\nfunction truncateUtf8(text: string, maxBytes: number): string | undefined {\n if (text.length <= maxBytes / 4) return undefined\n const bytes = Buffer.from(text, 'utf8')\n if (bytes.length <= maxBytes) return undefined\n // Step back to the first byte of a UTF-8 sequence so no character is split.\n let cut = maxBytes\n while (cut > 0 && ((bytes[cut] ?? 0) & 0xc0) === 0x80) cut -= 1\n return `${bytes.subarray(0, cut).toString('utf8')}…[truncated ${bytes.length - cut} bytes]`\n}\n\nfunction redactStringAt(text: string, path: string, state: WalkState): string {\n if (isPlaceholder(text)) return text\n // A known secret is an exact value, so it is cut out where it stands and the\n // text around it survives: an error message keeps its diagnosis.\n let output = text\n for (const form of state.knownSecrets) {\n if (!output.includes(form)) continue\n output = output.split(form).join(marker('known-secret'))\n record(state, path, 'credential', 'known-secret', 'redacted')\n }\n const dataUri = matchDataUri(output)\n if (dataUri) {\n if (DECODABLE_TEXT_MIME.test(dataUri.mime)) {\n const decoded = decodeDataUriPayload(dataUri.payload)\n if (decoded === undefined) {\n // Can't verify what an undecodable payload holds — fail closed rather\n // than pass it through as if it were opaque, harmless media.\n record(state, path, 'credential', 'data-uri-payload', 'redacted')\n return marker('data-uri-payload')\n }\n if (decodedPayloadIsUnsafe(decoded, dataUri.mime, state.knownSecrets)) {\n record(state, path, 'credential', 'data-uri-payload', 'redacted')\n return marker('data-uri-payload')\n }\n // Decoded clean: still opaque bytes to a downstream reader once\n // embedded, so it's subject to the ordinary media rule below, same as\n // any other data URI.\n }\n if (!state.rules.redactMedia) return output\n record(state, path, 'media', 'media', 'redacted')\n return marker('media')\n }\n // A value shape, or a whole-string base64 payload that holds a known secret\n // at any byte offset, replaces the whole string. The detectors themselves\n // only ever see a bounded prefix (`boundForScan`): a credential that lives\n // entirely beyond `maxStringBytes` would be truncated out of the output\n // below anyway, so scanning past the bound costs time without changing\n // what can leak. The untouched tail is reattached after the personal-data\n // pass so later truncation still sees (and cuts) the full length.\n const boundLen = Math.min(output.length, state.maxStringBytes)\n let scanTarget = output.slice(0, boundLen)\n const tail = output.slice(boundLen)\n const credential = credentialIn(scanTarget, state.knownSecrets)\n if (credential) {\n record(state, path, 'credential', credential, 'redacted')\n return marker(credential)\n }\n for (const detector of PERSONAL_DATA_DETECTORS) {\n if (detector.requires && !scanTarget.includes(detector.requires)) continue\n scanTarget = scanTarget.replace(detector.pattern, (match) => {\n if (detector.accept && !detector.accept(match)) return match\n record(state, path, 'personal-data', detector.id, 'redacted')\n return marker(detector.id)\n })\n }\n output = scanTarget + tail\n const truncated = truncateUtf8(output, state.maxStringBytes)\n if (truncated === undefined) return output\n record(state, path, 'raw-content', 'size-cap', 'truncated')\n return truncated\n}\n\nfunction pseudonym(value: string | number, state: WalkState): string {\n state.pseudonymKey ??= randomBytes(32)\n const digest = createHmac('sha256', state.pseudonymKey).update(String(value)).digest('hex')\n return `[ID:${digest.slice(0, 12)}]`\n}\n\nfunction redactKeyed(\n key: string,\n value: unknown,\n path: string,\n depth: number,\n state: WalkState,\n): unknown {\n const kind = classifyKeyName(key)\n if (value === null || value === undefined || typeof value === 'boolean') {\n return value\n }\n if (typeof value === 'string' && isPlaceholder(value)) return value\n // Numbers under a credential name are limits and counts (`password_max_age`), not secrets.\n if (kind === 'credential' && typeof value !== 'number') {\n record(state, path, 'credential', 'credential-key', 'redacted')\n return marker('credential-key')\n }\n if (\n kind === 'email' ||\n (kind === 'share-personal' && state.rules.redactKeys.has('share-personal'))\n ) {\n if (typeof value === 'string' || typeof value === 'number') {\n record(state, path, 'personal-data', 'personal-data-key', 'redacted')\n return marker('personal-data-key')\n }\n }\n if (kind === 'identifier' && state.rules.redactKeys.has('identifier')) {\n if (typeof value === 'string' || typeof value === 'number') {\n record(state, path, 'identifier', 'identifier-key', 'pseudonymized')\n return pseudonym(value, state)\n }\n }\n if (\n kind === 'raw-content' &&\n state.rules.redactKeys.has('raw-content') &&\n typeof value !== 'number'\n ) {\n record(state, path, 'raw-content', 'raw-content-key', 'redacted')\n return marker('raw-content-key')\n }\n return walk(value, path, depth + 1, state)\n}\n\nfunction walk(value: unknown, path: string, depth: number, state: WalkState): unknown {\n if (typeof value === 'string') return redactStringAt(value, path, state)\n if (value === null || typeof value !== 'object') return value\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n record(state, path, 'media', 'binary', 'redacted')\n return marker('binary')\n }\n if (value instanceof Date) return value\n if (depth > MAX_DEPTH) {\n record(state, path, 'raw-content', 'depth-limit', 'truncated')\n return marker('depth-limit')\n }\n if (state.seen.has(value)) {\n record(state, path, 'raw-content', 'circular', 'redacted')\n return marker('circular')\n }\n state.seen.add(value)\n try {\n if (Array.isArray(value)) {\n return value.map((item, index) => walk(item, pointer(path, index), depth + 1, state))\n }\n const out: Record<string, unknown> = {}\n let renamed = 0\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n let outKey = key\n const keyCredential = credentialIn(key, state.knownSecrets)\n // A personal-data value used AS a key (an email or card number mapping\n // to something) is just as reachable as one in a value — walk() only\n // ever inspects keys for a credential shape, so `{'alice@x.com': 3}`\n // passed through unchanged with verdict SAFE.\n const keyPersonalData = keyCredential ? undefined : detectPersonalData(key)[0]\n if (keyCredential) {\n renamed += 1\n outKey = `${marker(keyCredential)}#${renamed}`\n record(state, pointer(path, outKey), 'credential', keyCredential, 'redacted')\n } else if (keyPersonalData) {\n renamed += 1\n outKey = `${marker(keyPersonalData)}#${renamed}`\n record(state, pointer(path, outKey), 'personal-data', keyPersonalData, 'redacted')\n }\n out[outKey] = redactKeyed(key, item, pointer(path, outKey), depth, state)\n }\n return out\n } finally {\n state.seen.delete(value)\n }\n}\n\nfunction newReport(profile: RedactionProfile): RedactionReport {\n return {\n version: REDACTION_VERSION,\n profile,\n redactionCount: 0,\n byDetector: {},\n truncatedCount: 0,\n findings: [],\n }\n}\n\nfunction newState(options: RedactOptions, report?: RedactionReport): WalkState {\n const profile = options.profile ?? 'default'\n const rules = PROFILE_RULES[profile]\n if (!rules) throw new Error(`unknown redaction profile: ${String(profile)}`)\n const requested = options.maxStringBytes\n const maxStringBytes =\n typeof requested === 'number' && Number.isFinite(requested) && requested >= 0\n ? Math.min(Math.floor(requested), rules.maxStringBytes)\n : rules.maxStringBytes\n return {\n rules,\n maxStringBytes,\n knownSecrets: knownSecretForms(options.knownSecrets),\n report: report ?? newReport(profile),\n seen: new WeakSet(),\n }\n}\n\n/**\n * Return a redacted deep copy of `value` and a report of what changed. Pure:\n * the input is not mutated. Never throws on the value's shape; cycles, binary\n * data and nesting past 64 levels are replaced with markers.\n */\nexport function redact<T>(\n value: T,\n options: RedactOptions = {},\n): { value: T; report: RedactionReport } {\n const state = newState(options, options.report)\n const out = walk(value, '', 0, state) as T\n return { value: out, report: state.report }\n}\n\n/**\n * Redact one free-text string with the value detectors (no field name is\n * known). Pass `report` to accumulate counts across calls.\n */\nexport function redactText(text: string, options: RedactOptions = {}): string {\n const state = newState(options, options.report)\n return redactStringAt(text, '', state)\n}\n\n/** An empty report to accumulate `redactText` calls into. */\nexport function emptyRedactionReport(profile: RedactionProfile = 'default'): RedactionReport {\n return newReport(profile)\n}\n\n// ── Share-safety assessment ──────────────────────────────────────────────\n\ninterface ScanState {\n profile: RedactionProfile\n rules: ProfileRules\n knownSecrets: string[]\n findings: Map<string, ShareSafetyFinding>\n unreadable: string[]\n seen: WeakSet<object>\n}\n\nfunction flag(state: ScanState, path: string, category: SafetyCategory, detector: string): void {\n const severity = state.rules.severity[category]\n if (!severity) return\n const id = `${category}\\u0000${detector}`\n const existing = state.findings.get(id)\n if (existing) {\n existing.count += 1\n if (existing.paths.length < 5) existing.paths.push(path)\n return\n }\n state.findings.set(id, { category, detector, severity, count: 1, paths: [path] })\n}\n\nfunction scanString(text: string, path: string, state: ScanState): void {\n if (isPlaceholder(text)) return\n const dataUri = matchDataUri(text)\n if (dataUri) {\n scanDataUri(dataUri, path, state)\n return\n }\n const credential = credentialIn(text, state.knownSecrets)\n if (credential) {\n flag(state, path, 'credential', credential)\n return\n }\n for (const detector of detectPersonalData(text)) flag(state, path, 'personal-data', detector)\n}\n\nfunction scanDataUri(\n dataUri: { mime: string; payload: string },\n path: string,\n state: ScanState,\n): void {\n if (READABLE_IMAGE_MIME.test(dataUri.mime)) {\n flag(state, path, 'media', 'media')\n return\n }\n if (DECODABLE_TEXT_MIME.test(dataUri.mime)) {\n const decoded = decodeDataUriPayload(dataUri.payload)\n if (decoded === undefined) {\n state.unreadable.push(`${path || '/'}: data URI payload is not valid base64`)\n return\n }\n if (dataUri.mime === 'application/json') {\n try {\n scan(JSON.parse(decoded), path, 0, state)\n return\n } catch {\n // Not actually valid JSON despite the mime type — fall through to plain text.\n }\n }\n scanString(decoded, path, state)\n return\n }\n // audio/video/octet-stream/etc: bytes no text detector can read. A warning\n // under `default` (matches the existing image rule); under `share` and\n // `strict` — the profiles that actually gate whether something may be sent\n // off the machine — treat it as unreadable so the verdict is UNKNOWN\n // instead of silently allowing it through.\n if (state.profile === 'default') {\n flag(state, path, 'media', 'media')\n } else {\n state.unreadable.push(`${path || '/'}: ${dataUri.mime} data URI cannot be read`)\n }\n}\n\nfunction scanKeyed(\n key: string,\n value: unknown,\n path: string,\n depth: number,\n state: ScanState,\n): void {\n if (value === null || value === undefined || typeof value === 'boolean') return\n if (typeof value === 'string' && isPlaceholder(value)) return\n const category = classifyKey(key)\n if (category === 'credential' && typeof value !== 'number') {\n flag(state, path, 'credential', 'credential-key')\n return\n }\n const scalar = typeof value === 'string' || typeof value === 'number'\n if (category === 'personal-data' && scalar) {\n const kind = classifyKeyName(key)\n // Phone, IP and address fields are flagged from the share profile up; email always.\n if (kind === 'email' || state.profile !== 'default') {\n flag(state, path, 'personal-data', 'personal-data-key')\n return\n }\n }\n if (category === 'identifier' && scalar) flag(state, path, 'identifier', 'identifier-key')\n if (category === 'raw-content' && typeof value !== 'number')\n flag(state, path, 'raw-content', 'raw-content-key')\n scan(value, path, depth + 1, state)\n}\n\nfunction scan(value: unknown, path: string, depth: number, state: ScanState): void {\n if (typeof value === 'string') {\n scanString(value, path, state)\n return\n }\n if (value === null || typeof value !== 'object') return\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n state.unreadable.push(`${path || '/'}: binary data`)\n return\n }\n if (value instanceof Date) return\n if (depth > MAX_DEPTH) {\n state.unreadable.push(`${path || '/'}: nested deeper than ${MAX_DEPTH} levels`)\n return\n }\n if (state.seen.has(value)) {\n state.unreadable.push(`${path || '/'}: circular reference`)\n return\n }\n state.seen.add(value)\n try {\n if (Array.isArray(value)) {\n for (const [index, item] of value.entries())\n scan(item, pointer(path, index), depth + 1, state)\n return\n }\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n // A credential or personal-data value used as a key must not reach the\n // finding paths.\n const keyCredential = credentialIn(key, state.knownSecrets)\n const keyPersonalData = keyCredential ? undefined : detectPersonalData(key)[0]\n const keyDetector = keyCredential ?? keyPersonalData\n const segment = keyDetector ? marker(keyDetector) : key\n if (keyCredential) flag(state, pointer(path, segment), 'credential', keyCredential)\n else if (keyPersonalData)\n flag(state, pointer(path, segment), 'personal-data', keyPersonalData)\n scanKeyed(key, item, pointer(path, segment), depth, state)\n }\n } finally {\n state.seen.delete(value)\n }\n}\n\n/**\n * Read `value` without changing it and say whether it is safe to share under\n * `profile`. UNKNOWN when any part could not be read; UNSAFE when any\n * error-severity finding remains; SAFE_WITH_WARNINGS when only warnings\n * remain (raw content, embedded media, identifiers under `share`).\n */\nexport function assessShareSafety(value: unknown, options: AssessOptions = {}): ShareSafetyVerdict {\n const profile = options.profile ?? 'default'\n const rules = PROFILE_RULES[profile]\n if (!rules) throw new Error(`unknown redaction profile: ${String(profile)}`)\n const state: ScanState = {\n profile,\n rules,\n knownSecrets: knownSecretForms(options.knownSecrets),\n findings: new Map(),\n unreadable: [],\n seen: new WeakSet(),\n }\n scan(value, '', 0, state)\n return verdictFrom(profile, [...state.findings.values()], state.unreadable)\n}\n\n/**\n * One verdict over several parts (files in a directory, spans in a bundle).\n * Callers prefix each part's paths with its source before combining.\n */\nexport function combineVerdicts(\n profile: RedactionProfile,\n verdicts: readonly ShareSafetyVerdict[],\n unreadable: readonly string[] = [],\n): ShareSafetyVerdict {\n const findings = new Map<string, ShareSafetyFinding>()\n for (const verdict of verdicts) {\n for (const finding of verdict.findings) {\n const id = `${finding.category}\\u0000${finding.detector}`\n const existing = findings.get(id)\n if (!existing) {\n findings.set(id, { ...finding, paths: [...finding.paths] })\n continue\n }\n existing.count += finding.count\n for (const path of finding.paths) if (existing.paths.length < 5) existing.paths.push(path)\n }\n }\n return verdictFrom(\n profile,\n [...findings.values()],\n [...verdicts.flatMap((verdict) => verdict.unreadable), ...unreadable],\n )\n}\n\nfunction verdictFrom(\n profile: RedactionProfile,\n findings: readonly ShareSafetyFinding[],\n unreadable: readonly string[],\n): ShareSafetyVerdict {\n const status: ShareSafetyStatus =\n unreadable.length > 0\n ? 'UNKNOWN'\n : findings.some((finding) => finding.severity === 'error')\n ? 'UNSAFE'\n : findings.length > 0\n ? 'SAFE_WITH_WARNINGS'\n : 'SAFE'\n return { status, profile, findings: [...findings], unreadable: [...unreadable] }\n}\n\n/** Whether a verdict allows sharing: SAFE or SAFE_WITH_WARNINGS. UNSAFE and UNKNOWN refuse. */\nexport function shareAllowed(verdict: ShareSafetyVerdict): boolean {\n return verdict.status === 'SAFE' || verdict.status === 'SAFE_WITH_WARNINGS'\n}\n\n/**\n * Redact `value` under `profile`, then assess the redacted output. The\n * verdict describes what would actually be shared: a detector that failed to\n * remove something shows up as UNSAFE here.\n */\nexport function redactForShare<T>(\n value: T,\n options: RedactOptions = {},\n): { value: T; report: RedactionReport; verdict: ShareSafetyVerdict } {\n const redacted = redact(value, options)\n const verdict = assessShareSafety(redacted.value, {\n profile: options.profile,\n knownSecrets: options.knownSecrets,\n })\n return { value: redacted.value, report: redacted.report, verdict }\n}\n"],"mappings":"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"}
|
package/dist/rl.js
CHANGED
|
@@ -10,7 +10,7 @@ import { c as runTaskScore } from "./run-record-BRlM99rX.js";
|
|
|
10
10
|
import { n as campaignCellToRunRecord } from "./run-record-tNnlQIrD.js";
|
|
11
11
|
import { i as filterDeterministicallyRewarded, n as extractVerifiableReward, r as extractVerifiableRewardsFromRecords, t as detectRewardHacking } from "./reward-hacking-D0XwhVWE.js";
|
|
12
12
|
import { n as InMemoryTraceStore } from "./store-DNe_Uv1Q.js";
|
|
13
|
-
import { t as runEvalCampaign } from "./eval-campaign-
|
|
13
|
+
import { t as runEvalCampaign } from "./eval-campaign-CXT2WYUe.js";
|
|
14
14
|
import { s as assertRewardGate } from "./schema-C1aaAxTf.js";
|
|
15
15
|
import { n as isTrainingLineEligible, s as toSftRows$1, t as isSplitEligible } from "./exporters-DEcXbvgO.js";
|
|
16
16
|
import { t as mintRolloutRows } from "./mint-iCD-W43s.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { i as CostLedger } from "./cost-ledger-_IbkejCF.js";
|
|
2
2
|
import { p as Mutex } from "./journal-DvKCvjty.js";
|
|
3
3
|
import { N as RawAnalystFindingSchema } from "./kind-factory-CdPPHtGZ.js";
|
|
4
|
-
import { c as extractJsonPayload } from "./llm-client-
|
|
5
|
-
import { n as paidJsonChat, t as paidChat } from "./chat-json-call-
|
|
6
|
-
import { n as decodeRawFindingArray } from "./dspy-rlm-engine-
|
|
4
|
+
import { c as extractJsonPayload } from "./llm-client-c_bKHTXz.js";
|
|
5
|
+
import { n as paidJsonChat, t as paidChat } from "./chat-json-call-DnlDjpco.js";
|
|
6
|
+
import { n as decodeRawFindingArray } from "./dspy-rlm-engine-k_QdEBZo.js";
|
|
7
7
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { dirname } from "node:path";
|
|
@@ -777,4 +777,4 @@ async function runSemanticConceptJudge(input, options) {
|
|
|
777
777
|
//#endregion
|
|
778
778
|
export { diffFindings as a, defaultIsMaterial as i, runSemanticConceptJudge as n, createChatTraceEngine as o, FindingsStore as r, SEMANTIC_CONCEPT_JUDGE_VERSION as t };
|
|
779
779
|
|
|
780
|
-
//# sourceMappingURL=semantic-concept-judge-
|
|
780
|
+
//# sourceMappingURL=semantic-concept-judge-Bh5lvKGg.js.map
|