agent-inspect 6.31.3 → 6.31.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +1 -1
- package/SECURITY.md +2 -0
- package/docs/GETTING-STARTED.md +2 -0
- package/docs/SAFE-TRACE-SHARING.md +1 -0
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-SJ6FRNOE.mjs → chunk-LKEPABND.mjs} +86 -80
- package/packages/cli/dist/chunk-LKEPABND.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +449 -91
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +357 -14
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-YNEJOPRA.mjs → src-4WYF5RFI.mjs} +3 -3
- package/packages/cli/dist/{src-YNEJOPRA.mjs.map → src-4WYF5RFI.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +97 -30
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.mjs +13 -13
- package/packages/core/dist/checks.cjs +51 -49
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.mjs +5 -5
- package/packages/core/dist/{chunk-PBNBQRXV.mjs → chunk-2KJR6X4V.mjs} +9 -9
- package/packages/core/dist/chunk-2KJR6X4V.mjs.map +1 -0
- package/packages/core/dist/{chunk-26YJSETN.mjs → chunk-7DHSWDKB.mjs} +19 -6
- package/packages/core/dist/chunk-7DHSWDKB.mjs.map +1 -0
- package/packages/core/dist/{chunk-BGF5JDJN.mjs → chunk-INE5IWLN.mjs} +3 -3
- package/packages/core/dist/{chunk-BGF5JDJN.mjs.map → chunk-INE5IWLN.mjs.map} +1 -1
- package/packages/core/dist/{chunk-ZFJ2ICTC.mjs → chunk-MTMTXTJL.mjs} +5 -5
- package/packages/core/dist/{chunk-ZFJ2ICTC.mjs.map → chunk-MTMTXTJL.mjs.map} +1 -1
- package/packages/core/dist/{chunk-KWBO36PH.mjs → chunk-NY4ILMXK.mjs} +4 -4
- package/packages/core/dist/{chunk-KWBO36PH.mjs.map → chunk-NY4ILMXK.mjs.map} +1 -1
- package/packages/core/dist/{chunk-WN5PT4GV.mjs → chunk-OSGNGRHF.mjs} +3 -3
- package/packages/core/dist/{chunk-WN5PT4GV.mjs.map → chunk-OSGNGRHF.mjs.map} +1 -1
- package/packages/core/dist/{chunk-CBPWLHNQ.mjs → chunk-PKDBFBJ7.mjs} +5 -76
- package/packages/core/dist/chunk-PKDBFBJ7.mjs.map +1 -0
- package/packages/core/dist/{chunk-VU6O5QAH.mjs → chunk-VLVCLAPB.mjs} +83 -5
- package/packages/core/dist/chunk-VLVCLAPB.mjs.map +1 -0
- package/packages/core/dist/exporters.cjs +242 -6
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +143 -9
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/index.cjs +97 -8
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.mjs +6 -6
- package/packages/core/dist/logs.cjs +80 -2
- package/packages/core/dist/logs.cjs.map +1 -1
- package/packages/core/dist/logs.d.cts +2 -0
- package/packages/core/dist/logs.d.ts +2 -0
- package/packages/core/dist/logs.mjs +2 -2
- package/packages/core/dist/readers.cjs +2 -0
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.mjs +2 -2
- package/packages/core/dist/writers.cjs +96 -8
- package/packages/core/dist/writers.cjs.map +1 -1
- package/packages/core/dist/writers.mjs +7 -8
- package/packages/core/dist/writers.mjs.map +1 -1
- package/packages/cli/dist/chunk-SJ6FRNOE.mjs.map +0 -1
- package/packages/core/dist/chunk-26YJSETN.mjs.map +0 -1
- package/packages/core/dist/chunk-CBPWLHNQ.mjs.map +0 -1
- package/packages/core/dist/chunk-PBNBQRXV.mjs.map +0 -1
- package/packages/core/dist/chunk-VU6O5QAH.mjs.map +0 -1
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
|
|
3
|
+
// packages/core/src/logs/redactor.ts
|
|
4
|
+
|
|
5
|
+
// packages/core/src/safety/sensitive-key.ts
|
|
6
|
+
function keyHasExplicitSeparator(value) {
|
|
7
|
+
return /[_\-.]/.test(value);
|
|
8
|
+
}
|
|
9
|
+
function normalizeSensitiveKey(value) {
|
|
10
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
11
|
+
}
|
|
12
|
+
var NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
|
|
13
|
+
[
|
|
14
|
+
"tokens",
|
|
15
|
+
"max_tokens",
|
|
16
|
+
"min_tokens",
|
|
17
|
+
"ls_max_tokens",
|
|
18
|
+
"token_count",
|
|
19
|
+
"token_limit",
|
|
20
|
+
"token_budget",
|
|
21
|
+
"input_tokens",
|
|
22
|
+
"output_tokens",
|
|
23
|
+
"total_tokens",
|
|
24
|
+
"cached_tokens",
|
|
25
|
+
"prompt_tokens",
|
|
26
|
+
"completion_tokens"
|
|
27
|
+
].map(normalizeSensitiveKey)
|
|
28
|
+
);
|
|
29
|
+
var DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [
|
|
30
|
+
"authorization",
|
|
31
|
+
"cookie",
|
|
32
|
+
"token",
|
|
33
|
+
"access_token",
|
|
34
|
+
"accesstoken",
|
|
35
|
+
"auth_token",
|
|
36
|
+
"authtoken",
|
|
37
|
+
"refresh_token",
|
|
38
|
+
"refreshtoken",
|
|
39
|
+
"id_token",
|
|
40
|
+
"idtoken",
|
|
41
|
+
"bearer_token",
|
|
42
|
+
"bearertoken",
|
|
43
|
+
"api_token",
|
|
44
|
+
"apitoken",
|
|
45
|
+
"apikey",
|
|
46
|
+
"api_key",
|
|
47
|
+
"password",
|
|
48
|
+
"secret",
|
|
49
|
+
"email"
|
|
50
|
+
];
|
|
51
|
+
function isTokenCredentialKey(normalized) {
|
|
52
|
+
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
53
|
+
if (normalized === "token") return true;
|
|
54
|
+
if (normalized.endsWith("tokens")) return false;
|
|
55
|
+
return normalized.endsWith("token");
|
|
56
|
+
}
|
|
57
|
+
function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSITIVE_KEYS) {
|
|
58
|
+
if (!key) return false;
|
|
59
|
+
const normalized = normalizeSensitiveKey(key);
|
|
60
|
+
if (!normalized) return false;
|
|
61
|
+
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
62
|
+
const allowPrefixCompound = keyHasExplicitSeparator(key);
|
|
63
|
+
for (const sensitive of sensitiveKeys) {
|
|
64
|
+
const s = normalizeSensitiveKey(sensitive);
|
|
65
|
+
if (!s) continue;
|
|
66
|
+
if (s === "token") {
|
|
67
|
+
if (isTokenCredentialKey(normalized)) return true;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (normalized === s) return true;
|
|
71
|
+
if (normalized.endsWith(`_${s}`)) return true;
|
|
72
|
+
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
3
77
|
// packages/core/src/logs/redactor.ts
|
|
4
78
|
var DEFAULT_REDACT_KEYS = [
|
|
5
79
|
"authorization",
|
|
@@ -24,7 +98,7 @@ function compileRules(rules, extraKeys) {
|
|
|
24
98
|
const out = /* @__PURE__ */ new Map();
|
|
25
99
|
const set = (r) => {
|
|
26
100
|
const k = toKey(r.key);
|
|
27
|
-
out.set(k, { ...r, key: k });
|
|
101
|
+
out.set(k, { ...r, key: k, raw: r.raw ?? r.key });
|
|
28
102
|
};
|
|
29
103
|
for (const k of DEFAULT_REDACT_KEYS) {
|
|
30
104
|
set({ key: k, strategy: "full" });
|
|
@@ -53,9 +127,13 @@ var Redactor = class {
|
|
|
53
127
|
constructor(options) {
|
|
54
128
|
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
55
129
|
}
|
|
130
|
+
/** Field names this redactor treats as sensitive, for value-level helpers. */
|
|
131
|
+
get sensitiveKeys() {
|
|
132
|
+
return this.#rules.map((rule) => rule.raw ?? rule.key);
|
|
133
|
+
}
|
|
56
134
|
redactValue(key, value) {
|
|
57
135
|
const k = toKey(key);
|
|
58
|
-
const rule = this.#rules.find((r) => r.key === k);
|
|
136
|
+
const rule = this.#rules.find((r) => r.key === k) ?? this.#rules.find((r) => isCredentialSensitiveKey(key, [r.raw ?? r.key]));
|
|
59
137
|
if (!rule) {
|
|
60
138
|
return this.#redactNested(value);
|
|
61
139
|
}
|
|
@@ -94,6 +172,6 @@ var Redactor = class {
|
|
|
94
172
|
}
|
|
95
173
|
};
|
|
96
174
|
|
|
97
|
-
export { DEFAULT_REDACT_KEYS, Redactor };
|
|
98
|
-
//# sourceMappingURL=chunk-
|
|
99
|
-
//# sourceMappingURL=chunk-
|
|
175
|
+
export { DEFAULT_CREDENTIAL_SENSITIVE_KEYS, DEFAULT_REDACT_KEYS, Redactor, isCredentialSensitiveKey };
|
|
176
|
+
//# sourceMappingURL=chunk-VLVCLAPB.mjs.map
|
|
177
|
+
//# sourceMappingURL=chunk-VLVCLAPB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/safety/sensitive-key.ts","../src/logs/redactor.ts"],"names":[],"mappings":"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","file":"chunk-VLVCLAPB.mjs","sourcesContent":["/**\n * Contextual sensitive-key classification for safety checks and redaction.\n *\n * Avoids treating model token-configuration fields (ls_max_tokens, max_tokens,\n * token_count, …) as credentials solely because they contain the substring\n * \"token\". Value-based secret detectors remain separate.\n *\n * @experimental Shared classifier used by checks (6.14.2+); parity across\n * surfaces lands in the same patch train.\n */\n\n/** True when the original key already uses an explicit separator. */\nfunction keyHasExplicitSeparator(value: string): boolean {\n return /[_\\-.]/.test(value);\n}\n\n/**\n * Canonicalize field names so camelCase / kebab / dot / snake forms share a\n * snake_case shape the compound matcher can recognize (`userPassword` →\n * `user_password`).\n */\nexport function normalizeSensitiveKey(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\n/** Model / usage configuration keys that are not credentials by key alone. */\nexport const NON_CREDENTIAL_TOKEN_CONFIG_KEYS: ReadonlySet<string> = new Set(\n [\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 ].map(normalizeSensitiveKey),\n);\n\nexport const DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [\n \"authorization\",\n \"cookie\",\n \"token\",\n \"access_token\",\n \"accesstoken\",\n \"auth_token\",\n \"authtoken\",\n \"refresh_token\",\n \"refreshtoken\",\n \"id_token\",\n \"idtoken\",\n \"bearer_token\",\n \"bearertoken\",\n \"api_token\",\n \"apitoken\",\n \"apikey\",\n \"api_key\",\n \"password\",\n \"secret\",\n \"email\",\n] as const;\n\nfunction isTokenCredentialKey(normalized: string): boolean {\n if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;\n if (normalized === \"token\") return true;\n // access_token / refreshToken → *token, but not *tokens (max_tokens → max_tokens)\n if (normalized.endsWith(\"tokens\")) return false;\n return normalized.endsWith(\"token\");\n}\n\n/**\n * True when the field name looks credential-sensitive under the shared policy.\n *\n * Suffix compounds (`user_password`, `userPassword`) always match. Prefix\n * compounds (`email_note`) match only when the original key already contained\n * an explicit separator, so camelCase topic fields like `emailNote` stay for\n * value detectors instead of key redaction.\n */\nexport function isCredentialSensitiveKey(\n key: string | undefined,\n sensitiveKeys: readonly string[] = DEFAULT_CREDENTIAL_SENSITIVE_KEYS,\n): boolean {\n if (!key) return false;\n const normalized = normalizeSensitiveKey(key);\n if (!normalized) return false;\n if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;\n\n const allowPrefixCompound = keyHasExplicitSeparator(key);\n\n for (const sensitive of sensitiveKeys) {\n const s = normalizeSensitiveKey(sensitive);\n if (!s) continue;\n if (s === \"token\") {\n if (isTokenCredentialKey(normalized)) return true;\n continue;\n }\n if (normalized === s) return true;\n // Compound keys with explicit separators, plus camelCase owner+secret suffixes.\n if (normalized.endsWith(`_${s}`)) return true;\n if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;\n }\n return false;\n}\n","import crypto from \"node:crypto\";\n\nimport { isCredentialSensitiveKey } from \"../safety/sensitive-key.js\";\n\nimport type { RedactionRule } from \"../types/log-config.js\";\n\nexport const DEFAULT_REDACT_KEYS = [\n \"authorization\",\n \"cookie\",\n \"token\",\n \"apiKey\",\n \"password\",\n \"secret\",\n \"email\",\n] as const;\n\nexport interface RedactorOptions {\n rules?: RedactionRule[];\n /** Additional exact keys (case-insensitive) to redact in addition to defaults. */\n extraKeys?: readonly string[];\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction toKey(s: string): string {\n return s.toLowerCase();\n}\n\nfunction stableHash(value: string): string {\n const h = crypto.createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n return h.slice(0, 8);\n}\n\ntype CompiledRule = (\n | { key: string; strategy: \"full\" }\n | { key: string; strategy: \"prefix\"; keep: number }\n | { key: string; strategy: \"hash\" }\n) & { raw?: string };\n\nfunction compileRules(\n rules?: RedactionRule[],\n extraKeys?: readonly string[],\n): CompiledRule[] {\n const out = new Map<string, CompiledRule>();\n\n const set = (r: CompiledRule) => {\n const k = toKey(r.key);\n out.set(k, { ...r, key: k, raw: r.raw ?? r.key } as CompiledRule);\n };\n\n for (const k of DEFAULT_REDACT_KEYS) {\n set({ key: k, strategy: \"full\" });\n }\n\n for (const k of extraKeys ?? []) {\n if (typeof k === \"string\" && k.length > 0) {\n set({ key: k, strategy: \"full\" });\n }\n }\n\n for (const r of rules ?? []) {\n if (typeof r === \"string\") {\n set({ key: r, strategy: \"full\" });\n continue;\n }\n const key = r.key;\n if (r.strategy === \"full\") set({ key, strategy: \"full\" });\n if (r.strategy === \"hash\") set({ key, strategy: \"hash\" });\n if (r.strategy === \"prefix\") {\n set({ key, strategy: \"prefix\", keep: typeof r.keep === \"number\" ? r.keep : 8 });\n }\n }\n\n return [...out.values()];\n}\n\nexport class Redactor {\n readonly #rules: CompiledRule[];\n\n constructor(options?: RedactorOptions) {\n this.#rules = compileRules(options?.rules, options?.extraKeys);\n }\n\n /** Field names this redactor treats as sensitive, for value-level helpers. */\n get sensitiveKeys(): readonly string[] {\n return this.#rules.map((rule) => rule.raw ?? rule.key);\n }\n\n redactValue(key: string, value: unknown): unknown {\n const k = toKey(key);\n const rule =\n this.#rules.find((r) => r.key === k) ??\n this.#rules.find((r) => isCredentialSensitiveKey(key, [r.raw ?? r.key]));\n if (!rule) {\n return this.#redactNested(value);\n }\n\n if (rule.strategy === \"full\") return \"[REDACTED]\";\n const asString =\n typeof value === \"string\"\n ? value\n : typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\"\n ? String(value)\n : undefined;\n\n if (rule.strategy === \"prefix\") {\n if (asString === undefined) return \"[REDACTED]\";\n const keep = Math.max(0, Math.floor(rule.keep));\n return asString.length <= keep ? `${asString}…` : `${asString.slice(0, keep)}…`;\n }\n\n if (rule.strategy === \"hash\") {\n if (asString === undefined) return \"[HASH:unknown]\";\n return `[HASH:${stableHash(asString)}]`;\n }\n\n return this.#redactNested(value);\n }\n\n redactRecord(record: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(record)) {\n out[k] = this.redactValue(k, v);\n }\n return out;\n }\n\n #redactNested(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((v) => this.#redactNested(v));\n }\n if (isRecord(value)) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n out[k] = this.redactValue(k, v);\n }\n return out;\n }\n return value;\n }\n}\n\n"]}
|
|
@@ -13,6 +13,80 @@ var os__default = /*#__PURE__*/_interopDefault(os);
|
|
|
13
13
|
|
|
14
14
|
// packages/core/src/exporters/types.ts
|
|
15
15
|
var EXPORT_PAYLOAD_VERSION = "0.1.2";
|
|
16
|
+
|
|
17
|
+
// packages/core/src/safety/sensitive-key.ts
|
|
18
|
+
function keyHasExplicitSeparator(value) {
|
|
19
|
+
return /[_\-.]/.test(value);
|
|
20
|
+
}
|
|
21
|
+
function normalizeSensitiveKey(value) {
|
|
22
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
23
|
+
}
|
|
24
|
+
var NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
|
|
25
|
+
[
|
|
26
|
+
"tokens",
|
|
27
|
+
"max_tokens",
|
|
28
|
+
"min_tokens",
|
|
29
|
+
"ls_max_tokens",
|
|
30
|
+
"token_count",
|
|
31
|
+
"token_limit",
|
|
32
|
+
"token_budget",
|
|
33
|
+
"input_tokens",
|
|
34
|
+
"output_tokens",
|
|
35
|
+
"total_tokens",
|
|
36
|
+
"cached_tokens",
|
|
37
|
+
"prompt_tokens",
|
|
38
|
+
"completion_tokens"
|
|
39
|
+
].map(normalizeSensitiveKey)
|
|
40
|
+
);
|
|
41
|
+
var DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [
|
|
42
|
+
"authorization",
|
|
43
|
+
"cookie",
|
|
44
|
+
"token",
|
|
45
|
+
"access_token",
|
|
46
|
+
"accesstoken",
|
|
47
|
+
"auth_token",
|
|
48
|
+
"authtoken",
|
|
49
|
+
"refresh_token",
|
|
50
|
+
"refreshtoken",
|
|
51
|
+
"id_token",
|
|
52
|
+
"idtoken",
|
|
53
|
+
"bearer_token",
|
|
54
|
+
"bearertoken",
|
|
55
|
+
"api_token",
|
|
56
|
+
"apitoken",
|
|
57
|
+
"apikey",
|
|
58
|
+
"api_key",
|
|
59
|
+
"password",
|
|
60
|
+
"secret",
|
|
61
|
+
"email"
|
|
62
|
+
];
|
|
63
|
+
function isTokenCredentialKey(normalized) {
|
|
64
|
+
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
65
|
+
if (normalized === "token") return true;
|
|
66
|
+
if (normalized.endsWith("tokens")) return false;
|
|
67
|
+
return normalized.endsWith("token");
|
|
68
|
+
}
|
|
69
|
+
function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSITIVE_KEYS) {
|
|
70
|
+
if (!key) return false;
|
|
71
|
+
const normalized = normalizeSensitiveKey(key);
|
|
72
|
+
if (!normalized) return false;
|
|
73
|
+
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
74
|
+
const allowPrefixCompound = keyHasExplicitSeparator(key);
|
|
75
|
+
for (const sensitive of sensitiveKeys) {
|
|
76
|
+
const s = normalizeSensitiveKey(sensitive);
|
|
77
|
+
if (!s) continue;
|
|
78
|
+
if (s === "token") {
|
|
79
|
+
if (isTokenCredentialKey(normalized)) return true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (normalized === s) return true;
|
|
83
|
+
if (normalized.endsWith(`_${s}`)) return true;
|
|
84
|
+
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// packages/core/src/logs/redactor.ts
|
|
16
90
|
var DEFAULT_REDACT_KEYS = [
|
|
17
91
|
"authorization",
|
|
18
92
|
"cookie",
|
|
@@ -36,7 +110,7 @@ function compileRules(rules, extraKeys) {
|
|
|
36
110
|
const out = /* @__PURE__ */ new Map();
|
|
37
111
|
const set = (r) => {
|
|
38
112
|
const k = toKey(r.key);
|
|
39
|
-
out.set(k, { ...r, key: k });
|
|
113
|
+
out.set(k, { ...r, key: k, raw: r.raw ?? r.key });
|
|
40
114
|
};
|
|
41
115
|
for (const k of DEFAULT_REDACT_KEYS) {
|
|
42
116
|
set({ key: k, strategy: "full" });
|
|
@@ -65,9 +139,13 @@ var Redactor = class {
|
|
|
65
139
|
constructor(options) {
|
|
66
140
|
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
67
141
|
}
|
|
142
|
+
/** Field names this redactor treats as sensitive, for value-level helpers. */
|
|
143
|
+
get sensitiveKeys() {
|
|
144
|
+
return this.#rules.map((rule) => rule.raw ?? rule.key);
|
|
145
|
+
}
|
|
68
146
|
redactValue(key, value) {
|
|
69
147
|
const k = toKey(key);
|
|
70
|
-
const rule = this.#rules.find((r) => r.key === k);
|
|
148
|
+
const rule = this.#rules.find((r) => r.key === k) ?? this.#rules.find((r) => isCredentialSensitiveKey(key, [r.raw ?? r.key]));
|
|
71
149
|
if (!rule) {
|
|
72
150
|
return this.#redactNested(value);
|
|
73
151
|
}
|
|
@@ -106,6 +184,148 @@ var Redactor = class {
|
|
|
106
184
|
}
|
|
107
185
|
};
|
|
108
186
|
|
|
187
|
+
// packages/core/src/safety/credential-value-patterns.ts
|
|
188
|
+
var KEY_VALUE_SECRET_PATTERN = /\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=(?!\[(?:REDACTED(?::[^\]]*)?|HASH:[0-9a-f]{8})\](?![^\s"'\\&#?;/]))([^\s"'\\]{8,})/i;
|
|
189
|
+
var HIGH_CONFIDENCE_CREDENTIAL_PATTERNS = [
|
|
190
|
+
/^(?:basic|bearer|digest|apikey)\s+[a-z0-9._~+/=-]+$/i,
|
|
191
|
+
/\bbearer\s+[a-z0-9._~+/=-]{12,}\b/i,
|
|
192
|
+
/\b[a-z0-9_.-]+=[^;\s]+(?:;\s*[a-z0-9_.-]+=[^;\s]+)+/i,
|
|
193
|
+
/\beyJ[a-zA-Z0-9_-]{8,}\.[a-zA-Z0-9_-]{8,}\.[a-zA-Z0-9_-]{8,}\b/,
|
|
194
|
+
/\b(?:sk-(?:proj-)?[a-zA-Z0-9_-]{16,}|sk-ant-[a-zA-Z0-9_-]{16,}|AIza[0-9A-Za-z_-]{20,})\b/,
|
|
195
|
+
/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{20,}\b/,
|
|
196
|
+
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
|
|
197
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*-----END [A-Z ]*PRIVATE KEY-----/,
|
|
198
|
+
KEY_VALUE_SECRET_PATTERN
|
|
199
|
+
];
|
|
200
|
+
function stringContainsHighConfidenceCredential(value) {
|
|
201
|
+
for (const pattern of HIGH_CONFIDENCE_CREDENTIAL_PATTERNS) {
|
|
202
|
+
pattern.lastIndex = 0;
|
|
203
|
+
if (pattern.test(value)) {
|
|
204
|
+
pattern.lastIndex = 0;
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// packages/core/src/safety/url-redaction.ts
|
|
212
|
+
var HTTP_URL = /^https?:\/\/[^\s]+$/i;
|
|
213
|
+
var CONNECTION_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
214
|
+
"postgres:",
|
|
215
|
+
"postgresql:",
|
|
216
|
+
"mysql:",
|
|
217
|
+
"mariadb:",
|
|
218
|
+
"mongodb:",
|
|
219
|
+
"mongodb+srv:",
|
|
220
|
+
"redis:",
|
|
221
|
+
"rediss:",
|
|
222
|
+
"amqp:",
|
|
223
|
+
"amqps:"
|
|
224
|
+
]);
|
|
225
|
+
var CONNECTION_URI = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^\s]+$/i;
|
|
226
|
+
var UUID_SEGMENT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
227
|
+
var HEX_SEGMENT = /^[0-9a-f]{12,}$/i;
|
|
228
|
+
var NUMERIC_SEGMENT = /^\d{5,}$/;
|
|
229
|
+
var OPAQUE_SEGMENT = /^[A-Za-z0-9_-]{20,}$/;
|
|
230
|
+
function looksLikeHttpUrl(value) {
|
|
231
|
+
return HTTP_URL.test(value.trim());
|
|
232
|
+
}
|
|
233
|
+
function looksLikeConnectionUri(value) {
|
|
234
|
+
return CONNECTION_URI.test(value.trim());
|
|
235
|
+
}
|
|
236
|
+
function looksLikeUrlForRedaction(value) {
|
|
237
|
+
return looksLikeHttpUrl(value) || looksLikeConnectionUri(value);
|
|
238
|
+
}
|
|
239
|
+
function parseRedactableUrl(value) {
|
|
240
|
+
try {
|
|
241
|
+
const url = new URL(value.trim());
|
|
242
|
+
if (url.protocol === "http:" || url.protocol === "https:") return url;
|
|
243
|
+
if (CONNECTION_PROTOCOLS.has(url.protocol)) return url;
|
|
244
|
+
return void 0;
|
|
245
|
+
} catch {
|
|
246
|
+
return void 0;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function isHttpProtocol(protocol) {
|
|
250
|
+
return protocol === "http:" || protocol === "https:";
|
|
251
|
+
}
|
|
252
|
+
function isIdentifierSegment(segment) {
|
|
253
|
+
if (UUID_SEGMENT.test(segment)) return true;
|
|
254
|
+
if (HEX_SEGMENT.test(segment)) return true;
|
|
255
|
+
if (NUMERIC_SEGMENT.test(segment)) return true;
|
|
256
|
+
return OPAQUE_SEGMENT.test(segment) && /\d/.test(segment) && /[A-Za-z]/.test(segment);
|
|
257
|
+
}
|
|
258
|
+
function decodeParam(value) {
|
|
259
|
+
try {
|
|
260
|
+
return decodeURIComponent(value.replace(/\+/g, " "));
|
|
261
|
+
} catch {
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function redactParams(raw, options, replacement) {
|
|
266
|
+
let redacted = false;
|
|
267
|
+
const parts = raw.split("&").map((part) => {
|
|
268
|
+
if (part.length === 0) return part;
|
|
269
|
+
const separator = part.indexOf("=");
|
|
270
|
+
if (separator < 0) return part;
|
|
271
|
+
const rawKey = part.slice(0, separator);
|
|
272
|
+
const rawValue = part.slice(separator + 1);
|
|
273
|
+
const key = decodeParam(rawKey);
|
|
274
|
+
const value = decodeParam(rawValue);
|
|
275
|
+
if (isCredentialSensitiveKey(key, options.sensitiveKeys) || options.isSensitiveValue(value)) {
|
|
276
|
+
redacted = true;
|
|
277
|
+
return `${rawKey}=${replacement}`;
|
|
278
|
+
}
|
|
279
|
+
return part;
|
|
280
|
+
});
|
|
281
|
+
return { value: parts.join("&"), redacted };
|
|
282
|
+
}
|
|
283
|
+
function redactUrlString(value, options) {
|
|
284
|
+
const unchanged = {
|
|
285
|
+
value,
|
|
286
|
+
credentialRedacted: false,
|
|
287
|
+
identifiersMasked: false
|
|
288
|
+
};
|
|
289
|
+
if (!looksLikeUrlForRedaction(value)) return unchanged;
|
|
290
|
+
const url = parseRedactableUrl(value);
|
|
291
|
+
if (!url) return unchanged;
|
|
292
|
+
const replacement = options.replacement ?? "[REDACTED]";
|
|
293
|
+
const idPlaceholder = options.idPlaceholder ?? "[id]";
|
|
294
|
+
const http = isHttpProtocol(url.protocol);
|
|
295
|
+
let credentialRedacted = url.username.length > 0 || url.password.length > 0;
|
|
296
|
+
let identifiersMasked = false;
|
|
297
|
+
let pathname = url.pathname;
|
|
298
|
+
if (http && options.maskPathIds === true) {
|
|
299
|
+
pathname = url.pathname.split("/").map((segment) => {
|
|
300
|
+
if (segment.length === 0 || !isIdentifierSegment(decodeParam(segment))) {
|
|
301
|
+
return segment;
|
|
302
|
+
}
|
|
303
|
+
identifiersMasked = true;
|
|
304
|
+
return idPlaceholder;
|
|
305
|
+
}).join("/");
|
|
306
|
+
}
|
|
307
|
+
let search = "";
|
|
308
|
+
if (url.search.length > 1) {
|
|
309
|
+
const params = redactParams(url.search.slice(1), options, replacement);
|
|
310
|
+
if (params.redacted) credentialRedacted = true;
|
|
311
|
+
search = `?${params.value}`;
|
|
312
|
+
} else if (url.search.length === 1) {
|
|
313
|
+
search = "?";
|
|
314
|
+
}
|
|
315
|
+
let hash = url.hash;
|
|
316
|
+
if (url.hash.includes("=")) {
|
|
317
|
+
const params = redactParams(url.hash.slice(1), options, replacement);
|
|
318
|
+
if (params.redacted) credentialRedacted = true;
|
|
319
|
+
hash = `#${params.value}`;
|
|
320
|
+
}
|
|
321
|
+
if (!credentialRedacted && !identifiersMasked) return unchanged;
|
|
322
|
+
return {
|
|
323
|
+
value: `${url.protocol}//${url.host}${pathname}${search}${hash}`,
|
|
324
|
+
credentialRedacted,
|
|
325
|
+
identifiersMasked
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
109
329
|
// packages/core/src/redaction-profiles.ts
|
|
110
330
|
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
111
331
|
"userEmail",
|
|
@@ -208,21 +428,34 @@ function deepClone(value) {
|
|
|
208
428
|
}
|
|
209
429
|
return out;
|
|
210
430
|
}
|
|
211
|
-
function boundAttributeValues(record, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
431
|
+
function boundAttributeValues(record, sensitiveKeys, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
212
432
|
if (depth > 32) {
|
|
213
433
|
return { truncated: true, reason: "maxDepth" };
|
|
214
434
|
}
|
|
215
435
|
const out = {};
|
|
216
436
|
for (const [key, value] of Object.entries(record)) {
|
|
217
|
-
out[key] = boundValue(
|
|
437
|
+
out[key] = boundValue(
|
|
438
|
+
value,
|
|
439
|
+
key,
|
|
440
|
+
sensitiveKeys,
|
|
441
|
+
maxMetadataValueLength,
|
|
442
|
+
maxPreviewLength,
|
|
443
|
+
seen,
|
|
444
|
+
depth
|
|
445
|
+
);
|
|
218
446
|
}
|
|
219
447
|
return out;
|
|
220
448
|
}
|
|
221
|
-
function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
449
|
+
function boundValue(value, key, sensitiveKeys, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
222
450
|
if (value === null || typeof value !== "object") {
|
|
223
451
|
if (typeof value === "string") {
|
|
452
|
+
const rewritten = redactUrlString(value, {
|
|
453
|
+
sensitiveKeys,
|
|
454
|
+
isSensitiveValue: stringContainsHighConfidenceCredential,
|
|
455
|
+
maskPathIds: true
|
|
456
|
+
}).value;
|
|
224
457
|
return truncateStringForProfile(
|
|
225
|
-
|
|
458
|
+
stringContainsHighConfidenceCredential(rewritten) ? "[REDACTED]" : rewritten,
|
|
226
459
|
key,
|
|
227
460
|
maxMetadataValueLength,
|
|
228
461
|
maxPreviewLength
|
|
@@ -237,6 +470,7 @@ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen,
|
|
|
237
470
|
(item, index) => boundValue(
|
|
238
471
|
item,
|
|
239
472
|
String(index),
|
|
473
|
+
sensitiveKeys,
|
|
240
474
|
maxMetadataValueLength,
|
|
241
475
|
maxPreviewLength,
|
|
242
476
|
seen,
|
|
@@ -246,6 +480,7 @@ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen,
|
|
|
246
480
|
}
|
|
247
481
|
return boundAttributeValues(
|
|
248
482
|
value,
|
|
483
|
+
sensitiveKeys,
|
|
249
484
|
maxMetadataValueLength,
|
|
250
485
|
maxPreviewLength,
|
|
251
486
|
seen,
|
|
@@ -260,6 +495,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
|
|
|
260
495
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
261
496
|
const bounded = boundAttributeValues(
|
|
262
497
|
redacted,
|
|
498
|
+
[...DEFAULT_REDACT_KEYS, ...redactor.sensitiveKeys],
|
|
263
499
|
maxMetadataValueLength,
|
|
264
500
|
maxPreviewLength,
|
|
265
501
|
seen,
|