@agent-inspect/mcp-server 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/dist/{chunk-P2HSJJKS.mjs → chunk-FUNPQPC3.mjs} +418 -87
- package/dist/chunk-FUNPQPC3.mjs.map +1 -0
- package/dist/cli.cjs +416 -85
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.cjs +416 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
- package/dist/chunk-P2HSJJKS.mjs.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -46,6 +46,80 @@ function extractCorrelationMetadata(record) {
|
|
|
46
46
|
}
|
|
47
47
|
return found ? out : void 0;
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
// packages/core/src/safety/sensitive-key.ts
|
|
51
|
+
function keyHasExplicitSeparator(value) {
|
|
52
|
+
return /[_\-.]/.test(value);
|
|
53
|
+
}
|
|
54
|
+
function normalizeSensitiveKey(value) {
|
|
55
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
56
|
+
}
|
|
57
|
+
var NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
|
|
58
|
+
[
|
|
59
|
+
"tokens",
|
|
60
|
+
"max_tokens",
|
|
61
|
+
"min_tokens",
|
|
62
|
+
"ls_max_tokens",
|
|
63
|
+
"token_count",
|
|
64
|
+
"token_limit",
|
|
65
|
+
"token_budget",
|
|
66
|
+
"input_tokens",
|
|
67
|
+
"output_tokens",
|
|
68
|
+
"total_tokens",
|
|
69
|
+
"cached_tokens",
|
|
70
|
+
"prompt_tokens",
|
|
71
|
+
"completion_tokens"
|
|
72
|
+
].map(normalizeSensitiveKey)
|
|
73
|
+
);
|
|
74
|
+
var DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [
|
|
75
|
+
"authorization",
|
|
76
|
+
"cookie",
|
|
77
|
+
"token",
|
|
78
|
+
"access_token",
|
|
79
|
+
"accesstoken",
|
|
80
|
+
"auth_token",
|
|
81
|
+
"authtoken",
|
|
82
|
+
"refresh_token",
|
|
83
|
+
"refreshtoken",
|
|
84
|
+
"id_token",
|
|
85
|
+
"idtoken",
|
|
86
|
+
"bearer_token",
|
|
87
|
+
"bearertoken",
|
|
88
|
+
"api_token",
|
|
89
|
+
"apitoken",
|
|
90
|
+
"apikey",
|
|
91
|
+
"api_key",
|
|
92
|
+
"password",
|
|
93
|
+
"secret",
|
|
94
|
+
"email"
|
|
95
|
+
];
|
|
96
|
+
function isTokenCredentialKey(normalized) {
|
|
97
|
+
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
98
|
+
if (normalized === "token") return true;
|
|
99
|
+
if (normalized.endsWith("tokens")) return false;
|
|
100
|
+
return normalized.endsWith("token");
|
|
101
|
+
}
|
|
102
|
+
function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSITIVE_KEYS) {
|
|
103
|
+
if (!key) return false;
|
|
104
|
+
const normalized = normalizeSensitiveKey(key);
|
|
105
|
+
if (!normalized) return false;
|
|
106
|
+
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
107
|
+
const allowPrefixCompound = keyHasExplicitSeparator(key);
|
|
108
|
+
for (const sensitive of sensitiveKeys) {
|
|
109
|
+
const s = normalizeSensitiveKey(sensitive);
|
|
110
|
+
if (!s) continue;
|
|
111
|
+
if (s === "token") {
|
|
112
|
+
if (isTokenCredentialKey(normalized)) return true;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (normalized === s) return true;
|
|
116
|
+
if (normalized.endsWith(`_${s}`)) return true;
|
|
117
|
+
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// packages/core/src/logs/redactor.ts
|
|
49
123
|
var DEFAULT_REDACT_KEYS = [
|
|
50
124
|
"authorization",
|
|
51
125
|
"cookie",
|
|
@@ -69,7 +143,7 @@ function compileRules(rules, extraKeys) {
|
|
|
69
143
|
const out = /* @__PURE__ */ new Map();
|
|
70
144
|
const set = (r) => {
|
|
71
145
|
const k = toKey(r.key);
|
|
72
|
-
out.set(k, { ...r, key: k });
|
|
146
|
+
out.set(k, { ...r, key: k, raw: r.raw ?? r.key });
|
|
73
147
|
};
|
|
74
148
|
for (const k of DEFAULT_REDACT_KEYS) {
|
|
75
149
|
set({ key: k, strategy: "full" });
|
|
@@ -98,9 +172,13 @@ var Redactor = class {
|
|
|
98
172
|
constructor(options) {
|
|
99
173
|
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
100
174
|
}
|
|
175
|
+
/** Field names this redactor treats as sensitive, for value-level helpers. */
|
|
176
|
+
get sensitiveKeys() {
|
|
177
|
+
return this.#rules.map((rule) => rule.raw ?? rule.key);
|
|
178
|
+
}
|
|
101
179
|
redactValue(key, value) {
|
|
102
180
|
const k = toKey(key);
|
|
103
|
-
const rule = this.#rules.find((r) => r.key === k);
|
|
181
|
+
const rule = this.#rules.find((r) => r.key === k) ?? this.#rules.find((r) => isCredentialSensitiveKey(key, [r.raw ?? r.key]));
|
|
104
182
|
if (!rule) {
|
|
105
183
|
return this.#redactNested(value);
|
|
106
184
|
}
|
|
@@ -139,6 +217,30 @@ var Redactor = class {
|
|
|
139
217
|
}
|
|
140
218
|
};
|
|
141
219
|
|
|
220
|
+
// packages/core/src/safety/credential-value-patterns.ts
|
|
221
|
+
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;
|
|
222
|
+
var HIGH_CONFIDENCE_CREDENTIAL_PATTERNS = [
|
|
223
|
+
/^(?:basic|bearer|digest|apikey)\s+[a-z0-9._~+/=-]+$/i,
|
|
224
|
+
/\bbearer\s+[a-z0-9._~+/=-]{12,}\b/i,
|
|
225
|
+
/\b[a-z0-9_.-]+=[^;\s]+(?:;\s*[a-z0-9_.-]+=[^;\s]+)+/i,
|
|
226
|
+
/\beyJ[a-zA-Z0-9_-]{8,}\.[a-zA-Z0-9_-]{8,}\.[a-zA-Z0-9_-]{8,}\b/,
|
|
227
|
+
/\b(?:sk-(?:proj-)?[a-zA-Z0-9_-]{16,}|sk-ant-[a-zA-Z0-9_-]{16,}|AIza[0-9A-Za-z_-]{20,})\b/,
|
|
228
|
+
/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{20,}\b/,
|
|
229
|
+
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
|
|
230
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*-----END [A-Z ]*PRIVATE KEY-----/,
|
|
231
|
+
KEY_VALUE_SECRET_PATTERN
|
|
232
|
+
];
|
|
233
|
+
function stringContainsHighConfidenceCredential(value) {
|
|
234
|
+
for (const pattern of HIGH_CONFIDENCE_CREDENTIAL_PATTERNS) {
|
|
235
|
+
pattern.lastIndex = 0;
|
|
236
|
+
if (pattern.test(value)) {
|
|
237
|
+
pattern.lastIndex = 0;
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
|
|
142
244
|
// packages/core/src/redaction-profiles.ts
|
|
143
245
|
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
144
246
|
"userEmail",
|
|
@@ -2309,78 +2411,6 @@ function formatProgrammaticDiagnostic(code, detail) {
|
|
|
2309
2411
|
return `${code}: ${summary} Remediation: ${spec.remediation}`;
|
|
2310
2412
|
}
|
|
2311
2413
|
|
|
2312
|
-
// packages/core/src/safety/sensitive-key.ts
|
|
2313
|
-
function keyHasExplicitSeparator(value) {
|
|
2314
|
-
return /[_\-.]/.test(value);
|
|
2315
|
-
}
|
|
2316
|
-
function normalizeSensitiveKey(value) {
|
|
2317
|
-
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
2318
|
-
}
|
|
2319
|
-
var NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
|
|
2320
|
-
[
|
|
2321
|
-
"tokens",
|
|
2322
|
-
"max_tokens",
|
|
2323
|
-
"min_tokens",
|
|
2324
|
-
"ls_max_tokens",
|
|
2325
|
-
"token_count",
|
|
2326
|
-
"token_limit",
|
|
2327
|
-
"token_budget",
|
|
2328
|
-
"input_tokens",
|
|
2329
|
-
"output_tokens",
|
|
2330
|
-
"total_tokens",
|
|
2331
|
-
"cached_tokens",
|
|
2332
|
-
"prompt_tokens",
|
|
2333
|
-
"completion_tokens"
|
|
2334
|
-
].map(normalizeSensitiveKey)
|
|
2335
|
-
);
|
|
2336
|
-
var DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [
|
|
2337
|
-
"authorization",
|
|
2338
|
-
"cookie",
|
|
2339
|
-
"token",
|
|
2340
|
-
"access_token",
|
|
2341
|
-
"accesstoken",
|
|
2342
|
-
"auth_token",
|
|
2343
|
-
"authtoken",
|
|
2344
|
-
"refresh_token",
|
|
2345
|
-
"refreshtoken",
|
|
2346
|
-
"id_token",
|
|
2347
|
-
"idtoken",
|
|
2348
|
-
"bearer_token",
|
|
2349
|
-
"bearertoken",
|
|
2350
|
-
"api_token",
|
|
2351
|
-
"apitoken",
|
|
2352
|
-
"apikey",
|
|
2353
|
-
"api_key",
|
|
2354
|
-
"password",
|
|
2355
|
-
"secret",
|
|
2356
|
-
"email"
|
|
2357
|
-
];
|
|
2358
|
-
function isTokenCredentialKey(normalized) {
|
|
2359
|
-
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
2360
|
-
if (normalized === "token") return true;
|
|
2361
|
-
if (normalized.endsWith("tokens")) return false;
|
|
2362
|
-
return normalized.endsWith("token");
|
|
2363
|
-
}
|
|
2364
|
-
function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSITIVE_KEYS) {
|
|
2365
|
-
if (!key) return false;
|
|
2366
|
-
const normalized = normalizeSensitiveKey(key);
|
|
2367
|
-
if (!normalized) return false;
|
|
2368
|
-
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
2369
|
-
const allowPrefixCompound = keyHasExplicitSeparator(key);
|
|
2370
|
-
for (const sensitive of sensitiveKeys) {
|
|
2371
|
-
const s = normalizeSensitiveKey(sensitive);
|
|
2372
|
-
if (!s) continue;
|
|
2373
|
-
if (s === "token") {
|
|
2374
|
-
if (isTokenCredentialKey(normalized)) return true;
|
|
2375
|
-
continue;
|
|
2376
|
-
}
|
|
2377
|
-
if (normalized === s) return true;
|
|
2378
|
-
if (normalized.endsWith(`_${s}`)) return true;
|
|
2379
|
-
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
2380
|
-
}
|
|
2381
|
-
return false;
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
2414
|
// packages/core/src/checks/logical-events.ts
|
|
2385
2415
|
function isRecord6(value) {
|
|
2386
2416
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -3331,7 +3361,7 @@ var DEFAULT_SECRET_PATTERNS = [
|
|
|
3331
3361
|
// Keep in sync with packages/redact/src/key-value-secret.ts (KEY_VALUE_SECRET_PATTERN_SOURCE).
|
|
3332
3362
|
{
|
|
3333
3363
|
id: "key-value-secret",
|
|
3334
|
-
pattern: /\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=([^\s"'\\]{8,})/i
|
|
3364
|
+
pattern: /\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=(?!\[(?:REDACTED(?::[^\]]*)?|HASH:[0-9a-f]{8})\](?![^\s"'\\&#?;/]))([^\s"'\\]{8,})/i
|
|
3335
3365
|
}
|
|
3336
3366
|
];
|
|
3337
3367
|
function compareStrings(a, b) {
|
|
@@ -6672,6 +6702,124 @@ function openTrace(input, options = {}) {
|
|
|
6672
6702
|
// packages/core/src/exporters/types.ts
|
|
6673
6703
|
var EXPORT_PAYLOAD_VERSION = "0.1.2";
|
|
6674
6704
|
|
|
6705
|
+
// packages/core/src/safety/url-redaction.ts
|
|
6706
|
+
var HTTP_URL = /^https?:\/\/[^\s]+$/i;
|
|
6707
|
+
var CONNECTION_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
6708
|
+
"postgres:",
|
|
6709
|
+
"postgresql:",
|
|
6710
|
+
"mysql:",
|
|
6711
|
+
"mariadb:",
|
|
6712
|
+
"mongodb:",
|
|
6713
|
+
"mongodb+srv:",
|
|
6714
|
+
"redis:",
|
|
6715
|
+
"rediss:",
|
|
6716
|
+
"amqp:",
|
|
6717
|
+
"amqps:"
|
|
6718
|
+
]);
|
|
6719
|
+
var CONNECTION_URI = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^\s]+$/i;
|
|
6720
|
+
var UUID_SEGMENT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
6721
|
+
var HEX_SEGMENT = /^[0-9a-f]{12,}$/i;
|
|
6722
|
+
var NUMERIC_SEGMENT = /^\d{5,}$/;
|
|
6723
|
+
var OPAQUE_SEGMENT = /^[A-Za-z0-9_-]{20,}$/;
|
|
6724
|
+
function looksLikeHttpUrl(value) {
|
|
6725
|
+
return HTTP_URL.test(value.trim());
|
|
6726
|
+
}
|
|
6727
|
+
function looksLikeConnectionUri(value) {
|
|
6728
|
+
return CONNECTION_URI.test(value.trim());
|
|
6729
|
+
}
|
|
6730
|
+
function looksLikeUrlForRedaction(value) {
|
|
6731
|
+
return looksLikeHttpUrl(value) || looksLikeConnectionUri(value);
|
|
6732
|
+
}
|
|
6733
|
+
function parseRedactableUrl(value) {
|
|
6734
|
+
try {
|
|
6735
|
+
const url = new URL(value.trim());
|
|
6736
|
+
if (url.protocol === "http:" || url.protocol === "https:") return url;
|
|
6737
|
+
if (CONNECTION_PROTOCOLS.has(url.protocol)) return url;
|
|
6738
|
+
return void 0;
|
|
6739
|
+
} catch {
|
|
6740
|
+
return void 0;
|
|
6741
|
+
}
|
|
6742
|
+
}
|
|
6743
|
+
function isHttpProtocol(protocol) {
|
|
6744
|
+
return protocol === "http:" || protocol === "https:";
|
|
6745
|
+
}
|
|
6746
|
+
function isIdentifierSegment(segment) {
|
|
6747
|
+
if (UUID_SEGMENT.test(segment)) return true;
|
|
6748
|
+
if (HEX_SEGMENT.test(segment)) return true;
|
|
6749
|
+
if (NUMERIC_SEGMENT.test(segment)) return true;
|
|
6750
|
+
return OPAQUE_SEGMENT.test(segment) && /\d/.test(segment) && /[A-Za-z]/.test(segment);
|
|
6751
|
+
}
|
|
6752
|
+
function decodeParam(value) {
|
|
6753
|
+
try {
|
|
6754
|
+
return decodeURIComponent(value.replace(/\+/g, " "));
|
|
6755
|
+
} catch {
|
|
6756
|
+
return value;
|
|
6757
|
+
}
|
|
6758
|
+
}
|
|
6759
|
+
function redactParams(raw, options, replacement) {
|
|
6760
|
+
let redacted = false;
|
|
6761
|
+
const parts = raw.split("&").map((part) => {
|
|
6762
|
+
if (part.length === 0) return part;
|
|
6763
|
+
const separator = part.indexOf("=");
|
|
6764
|
+
if (separator < 0) return part;
|
|
6765
|
+
const rawKey = part.slice(0, separator);
|
|
6766
|
+
const rawValue = part.slice(separator + 1);
|
|
6767
|
+
const key = decodeParam(rawKey);
|
|
6768
|
+
const value = decodeParam(rawValue);
|
|
6769
|
+
if (isCredentialSensitiveKey(key, options.sensitiveKeys) || options.isSensitiveValue(value)) {
|
|
6770
|
+
redacted = true;
|
|
6771
|
+
return `${rawKey}=${replacement}`;
|
|
6772
|
+
}
|
|
6773
|
+
return part;
|
|
6774
|
+
});
|
|
6775
|
+
return { value: parts.join("&"), redacted };
|
|
6776
|
+
}
|
|
6777
|
+
function redactUrlString(value, options) {
|
|
6778
|
+
const unchanged = {
|
|
6779
|
+
value,
|
|
6780
|
+
credentialRedacted: false,
|
|
6781
|
+
identifiersMasked: false
|
|
6782
|
+
};
|
|
6783
|
+
if (!looksLikeUrlForRedaction(value)) return unchanged;
|
|
6784
|
+
const url = parseRedactableUrl(value);
|
|
6785
|
+
if (!url) return unchanged;
|
|
6786
|
+
const replacement = options.replacement ?? "[REDACTED]";
|
|
6787
|
+
const idPlaceholder = options.idPlaceholder ?? "[id]";
|
|
6788
|
+
const http = isHttpProtocol(url.protocol);
|
|
6789
|
+
let credentialRedacted = url.username.length > 0 || url.password.length > 0;
|
|
6790
|
+
let identifiersMasked = false;
|
|
6791
|
+
let pathname = url.pathname;
|
|
6792
|
+
if (http && options.maskPathIds === true) {
|
|
6793
|
+
pathname = url.pathname.split("/").map((segment) => {
|
|
6794
|
+
if (segment.length === 0 || !isIdentifierSegment(decodeParam(segment))) {
|
|
6795
|
+
return segment;
|
|
6796
|
+
}
|
|
6797
|
+
identifiersMasked = true;
|
|
6798
|
+
return idPlaceholder;
|
|
6799
|
+
}).join("/");
|
|
6800
|
+
}
|
|
6801
|
+
let search = "";
|
|
6802
|
+
if (url.search.length > 1) {
|
|
6803
|
+
const params = redactParams(url.search.slice(1), options, replacement);
|
|
6804
|
+
if (params.redacted) credentialRedacted = true;
|
|
6805
|
+
search = `?${params.value}`;
|
|
6806
|
+
} else if (url.search.length === 1) {
|
|
6807
|
+
search = "?";
|
|
6808
|
+
}
|
|
6809
|
+
let hash = url.hash;
|
|
6810
|
+
if (url.hash.includes("=")) {
|
|
6811
|
+
const params = redactParams(url.hash.slice(1), options, replacement);
|
|
6812
|
+
if (params.redacted) credentialRedacted = true;
|
|
6813
|
+
hash = `#${params.value}`;
|
|
6814
|
+
}
|
|
6815
|
+
if (!credentialRedacted && !identifiersMasked) return unchanged;
|
|
6816
|
+
return {
|
|
6817
|
+
value: `${url.protocol}//${url.host}${pathname}${search}${hash}`,
|
|
6818
|
+
credentialRedacted,
|
|
6819
|
+
identifiersMasked
|
|
6820
|
+
};
|
|
6821
|
+
}
|
|
6822
|
+
|
|
6675
6823
|
// packages/core/src/exporters/redact-export.ts
|
|
6676
6824
|
function isRecord11(value) {
|
|
6677
6825
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -6689,21 +6837,34 @@ function deepClone(value) {
|
|
|
6689
6837
|
}
|
|
6690
6838
|
return out;
|
|
6691
6839
|
}
|
|
6692
|
-
function boundAttributeValues(record, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
6840
|
+
function boundAttributeValues(record, sensitiveKeys, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
6693
6841
|
if (depth > 32) {
|
|
6694
6842
|
return { truncated: true, reason: "maxDepth" };
|
|
6695
6843
|
}
|
|
6696
6844
|
const out = {};
|
|
6697
6845
|
for (const [key, value] of Object.entries(record)) {
|
|
6698
|
-
out[key] = boundValue(
|
|
6846
|
+
out[key] = boundValue(
|
|
6847
|
+
value,
|
|
6848
|
+
key,
|
|
6849
|
+
sensitiveKeys,
|
|
6850
|
+
maxMetadataValueLength,
|
|
6851
|
+
maxPreviewLength,
|
|
6852
|
+
seen,
|
|
6853
|
+
depth
|
|
6854
|
+
);
|
|
6699
6855
|
}
|
|
6700
6856
|
return out;
|
|
6701
6857
|
}
|
|
6702
|
-
function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
6858
|
+
function boundValue(value, key, sensitiveKeys, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
6703
6859
|
if (value === null || typeof value !== "object") {
|
|
6704
6860
|
if (typeof value === "string") {
|
|
6861
|
+
const rewritten = redactUrlString(value, {
|
|
6862
|
+
sensitiveKeys,
|
|
6863
|
+
isSensitiveValue: stringContainsHighConfidenceCredential,
|
|
6864
|
+
maskPathIds: true
|
|
6865
|
+
}).value;
|
|
6705
6866
|
return truncateStringForProfile(
|
|
6706
|
-
|
|
6867
|
+
stringContainsHighConfidenceCredential(rewritten) ? "[REDACTED]" : rewritten,
|
|
6707
6868
|
key,
|
|
6708
6869
|
maxMetadataValueLength,
|
|
6709
6870
|
maxPreviewLength
|
|
@@ -6718,6 +6879,7 @@ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen,
|
|
|
6718
6879
|
(item, index) => boundValue(
|
|
6719
6880
|
item,
|
|
6720
6881
|
String(index),
|
|
6882
|
+
sensitiveKeys,
|
|
6721
6883
|
maxMetadataValueLength,
|
|
6722
6884
|
maxPreviewLength,
|
|
6723
6885
|
seen,
|
|
@@ -6727,6 +6889,7 @@ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen,
|
|
|
6727
6889
|
}
|
|
6728
6890
|
return boundAttributeValues(
|
|
6729
6891
|
value,
|
|
6892
|
+
sensitiveKeys,
|
|
6730
6893
|
maxMetadataValueLength,
|
|
6731
6894
|
maxPreviewLength,
|
|
6732
6895
|
seen,
|
|
@@ -6741,6 +6904,7 @@ function redactEventAttributes(attrs2, redactor, maxMetadataValueLength, maxPrev
|
|
|
6741
6904
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
6742
6905
|
const bounded = boundAttributeValues(
|
|
6743
6906
|
redacted,
|
|
6907
|
+
[...DEFAULT_REDACT_KEYS, ...redactor.sensitiveKeys],
|
|
6744
6908
|
maxMetadataValueLength,
|
|
6745
6909
|
maxPreviewLength,
|
|
6746
6910
|
seen,
|
|
@@ -7411,14 +7575,132 @@ function isCredentialSensitiveKey2(key, sensitiveKeys) {
|
|
|
7411
7575
|
}
|
|
7412
7576
|
|
|
7413
7577
|
// packages/redact/src/key-value-secret.ts
|
|
7414
|
-
var KEY_VALUE_SECRET_PATTERN_SOURCE = String.raw`\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=([^\s"'\\]{8,})`;
|
|
7415
|
-
var
|
|
7578
|
+
var KEY_VALUE_SECRET_PATTERN_SOURCE = String.raw`\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=(?!\[(?:REDACTED(?::[^\]]*)?|HASH:[0-9a-f]{8})\](?![^\s"'\\&#?;/]))([^\s"'\\]{8,})`;
|
|
7579
|
+
var KEY_VALUE_SECRET_PATTERN2 = new RegExp(
|
|
7416
7580
|
KEY_VALUE_SECRET_PATTERN_SOURCE,
|
|
7417
7581
|
"i"
|
|
7418
7582
|
);
|
|
7419
7583
|
function valueContainsKeyValueSecret(value) {
|
|
7420
|
-
|
|
7421
|
-
return
|
|
7584
|
+
KEY_VALUE_SECRET_PATTERN2.lastIndex = 0;
|
|
7585
|
+
return KEY_VALUE_SECRET_PATTERN2.test(value);
|
|
7586
|
+
}
|
|
7587
|
+
|
|
7588
|
+
// packages/redact/src/url-redaction.ts
|
|
7589
|
+
var HTTP_URL2 = /^https?:\/\/[^\s]+$/i;
|
|
7590
|
+
var CONNECTION_PROTOCOLS2 = /* @__PURE__ */ new Set([
|
|
7591
|
+
"postgres:",
|
|
7592
|
+
"postgresql:",
|
|
7593
|
+
"mysql:",
|
|
7594
|
+
"mariadb:",
|
|
7595
|
+
"mongodb:",
|
|
7596
|
+
"mongodb+srv:",
|
|
7597
|
+
"redis:",
|
|
7598
|
+
"rediss:",
|
|
7599
|
+
"amqp:",
|
|
7600
|
+
"amqps:"
|
|
7601
|
+
]);
|
|
7602
|
+
var CONNECTION_URI2 = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^\s]+$/i;
|
|
7603
|
+
var UUID_SEGMENT2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7604
|
+
var HEX_SEGMENT2 = /^[0-9a-f]{12,}$/i;
|
|
7605
|
+
var NUMERIC_SEGMENT2 = /^\d{5,}$/;
|
|
7606
|
+
var OPAQUE_SEGMENT2 = /^[A-Za-z0-9_-]{20,}$/;
|
|
7607
|
+
function looksLikeHttpUrl2(value) {
|
|
7608
|
+
return HTTP_URL2.test(value.trim());
|
|
7609
|
+
}
|
|
7610
|
+
function looksLikeConnectionUri2(value) {
|
|
7611
|
+
return CONNECTION_URI2.test(value.trim());
|
|
7612
|
+
}
|
|
7613
|
+
function looksLikeUrlForRedaction2(value) {
|
|
7614
|
+
return looksLikeHttpUrl2(value) || looksLikeConnectionUri2(value);
|
|
7615
|
+
}
|
|
7616
|
+
function parseRedactableUrl2(value) {
|
|
7617
|
+
try {
|
|
7618
|
+
const url = new URL(value.trim());
|
|
7619
|
+
if (url.protocol === "http:" || url.protocol === "https:") return url;
|
|
7620
|
+
if (CONNECTION_PROTOCOLS2.has(url.protocol)) return url;
|
|
7621
|
+
return void 0;
|
|
7622
|
+
} catch {
|
|
7623
|
+
return void 0;
|
|
7624
|
+
}
|
|
7625
|
+
}
|
|
7626
|
+
function isHttpProtocol2(protocol) {
|
|
7627
|
+
return protocol === "http:" || protocol === "https:";
|
|
7628
|
+
}
|
|
7629
|
+
function isIdentifierSegment2(segment) {
|
|
7630
|
+
if (UUID_SEGMENT2.test(segment)) return true;
|
|
7631
|
+
if (HEX_SEGMENT2.test(segment)) return true;
|
|
7632
|
+
if (NUMERIC_SEGMENT2.test(segment)) return true;
|
|
7633
|
+
return OPAQUE_SEGMENT2.test(segment) && /\d/.test(segment) && /[A-Za-z]/.test(segment);
|
|
7634
|
+
}
|
|
7635
|
+
function decodeParam2(value) {
|
|
7636
|
+
try {
|
|
7637
|
+
return decodeURIComponent(value.replace(/\+/g, " "));
|
|
7638
|
+
} catch {
|
|
7639
|
+
return value;
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
function redactParams2(raw, options, replacement) {
|
|
7643
|
+
let redacted = false;
|
|
7644
|
+
const parts = raw.split("&").map((part) => {
|
|
7645
|
+
if (part.length === 0) return part;
|
|
7646
|
+
const separator = part.indexOf("=");
|
|
7647
|
+
if (separator < 0) return part;
|
|
7648
|
+
const rawKey = part.slice(0, separator);
|
|
7649
|
+
const rawValue = part.slice(separator + 1);
|
|
7650
|
+
const key = decodeParam2(rawKey);
|
|
7651
|
+
const value = decodeParam2(rawValue);
|
|
7652
|
+
if (isCredentialSensitiveKey2(key, options.sensitiveKeys) || options.isSensitiveValue(value)) {
|
|
7653
|
+
redacted = true;
|
|
7654
|
+
return `${rawKey}=${replacement}`;
|
|
7655
|
+
}
|
|
7656
|
+
return part;
|
|
7657
|
+
});
|
|
7658
|
+
return { value: parts.join("&"), redacted };
|
|
7659
|
+
}
|
|
7660
|
+
function redactUrlString2(value, options) {
|
|
7661
|
+
const unchanged = {
|
|
7662
|
+
value,
|
|
7663
|
+
credentialRedacted: false,
|
|
7664
|
+
identifiersMasked: false
|
|
7665
|
+
};
|
|
7666
|
+
if (!looksLikeUrlForRedaction2(value)) return unchanged;
|
|
7667
|
+
const url = parseRedactableUrl2(value);
|
|
7668
|
+
if (!url) return unchanged;
|
|
7669
|
+
const replacement = options.replacement ?? "[REDACTED]";
|
|
7670
|
+
const idPlaceholder = options.idPlaceholder ?? "[id]";
|
|
7671
|
+
const http = isHttpProtocol2(url.protocol);
|
|
7672
|
+
let credentialRedacted = url.username.length > 0 || url.password.length > 0;
|
|
7673
|
+
let identifiersMasked = false;
|
|
7674
|
+
let pathname = url.pathname;
|
|
7675
|
+
if (http && options.maskPathIds === true) {
|
|
7676
|
+
pathname = url.pathname.split("/").map((segment) => {
|
|
7677
|
+
if (segment.length === 0 || !isIdentifierSegment2(decodeParam2(segment))) {
|
|
7678
|
+
return segment;
|
|
7679
|
+
}
|
|
7680
|
+
identifiersMasked = true;
|
|
7681
|
+
return idPlaceholder;
|
|
7682
|
+
}).join("/");
|
|
7683
|
+
}
|
|
7684
|
+
let search = "";
|
|
7685
|
+
if (url.search.length > 1) {
|
|
7686
|
+
const params = redactParams2(url.search.slice(1), options, replacement);
|
|
7687
|
+
if (params.redacted) credentialRedacted = true;
|
|
7688
|
+
search = `?${params.value}`;
|
|
7689
|
+
} else if (url.search.length === 1) {
|
|
7690
|
+
search = "?";
|
|
7691
|
+
}
|
|
7692
|
+
let hash = url.hash;
|
|
7693
|
+
if (url.hash.includes("=")) {
|
|
7694
|
+
const params = redactParams2(url.hash.slice(1), options, replacement);
|
|
7695
|
+
if (params.redacted) credentialRedacted = true;
|
|
7696
|
+
hash = `#${params.value}`;
|
|
7697
|
+
}
|
|
7698
|
+
if (!credentialRedacted && !identifiersMasked) return unchanged;
|
|
7699
|
+
return {
|
|
7700
|
+
value: `${url.protocol}//${url.host}${pathname}${search}${hash}`,
|
|
7701
|
+
credentialRedacted,
|
|
7702
|
+
identifiersMasked
|
|
7703
|
+
};
|
|
7422
7704
|
}
|
|
7423
7705
|
|
|
7424
7706
|
// packages/redact/src/index.ts
|
|
@@ -7487,7 +7769,9 @@ function findCompiledKeyRule(key, rules) {
|
|
|
7487
7769
|
const exact = toKey2(key);
|
|
7488
7770
|
const direct = rules.find((candidate) => candidate.key === exact);
|
|
7489
7771
|
if (direct) return direct;
|
|
7490
|
-
return rules.find(
|
|
7772
|
+
return rules.find(
|
|
7773
|
+
(candidate) => isCredentialSensitiveKey2(key, [candidate.raw ?? candidate.key])
|
|
7774
|
+
);
|
|
7491
7775
|
}
|
|
7492
7776
|
function stableHash2(value) {
|
|
7493
7777
|
const hash = crypto__default.default.createHash("sha256").update(value, "utf8").digest("hex");
|
|
@@ -7686,7 +7970,7 @@ function compileRules2(rules, extraKeys) {
|
|
|
7686
7970
|
const out = /* @__PURE__ */ new Map();
|
|
7687
7971
|
const set = (rule) => {
|
|
7688
7972
|
const key = toKey2(rule.key);
|
|
7689
|
-
out.set(key, { ...rule, key });
|
|
7973
|
+
out.set(key, { ...rule, key, raw: rule.raw ?? rule.key });
|
|
7690
7974
|
};
|
|
7691
7975
|
for (const key of DEFAULT_REDACT_KEYS2) {
|
|
7692
7976
|
set({ key, strategy: "full" });
|
|
@@ -7765,6 +8049,7 @@ function createRedactionProfile(profile = "local") {
|
|
|
7765
8049
|
}
|
|
7766
8050
|
var Redactor2 = class {
|
|
7767
8051
|
#rules;
|
|
8052
|
+
#sensitiveKeys;
|
|
7768
8053
|
#detectors;
|
|
7769
8054
|
#profile;
|
|
7770
8055
|
#replacement;
|
|
@@ -7777,6 +8062,7 @@ var Redactor2 = class {
|
|
|
7777
8062
|
...resolved.extraKeys,
|
|
7778
8063
|
...options?.extraKeys ?? []
|
|
7779
8064
|
]);
|
|
8065
|
+
this.#sensitiveKeys = this.#rules.map((rule) => rule.raw ?? rule.key);
|
|
7780
8066
|
this.#detectors = [
|
|
7781
8067
|
...builtInDetectorsForProfile(this.#profile),
|
|
7782
8068
|
...options?.detectors ?? []
|
|
@@ -7810,6 +8096,14 @@ var Redactor2 = class {
|
|
|
7810
8096
|
#recordFinding(state, finding) {
|
|
7811
8097
|
if (this.#collectFindings) state.findings.push(finding);
|
|
7812
8098
|
}
|
|
8099
|
+
#detect(value, key, path17) {
|
|
8100
|
+
for (const detector of this.#detectors) {
|
|
8101
|
+
for (const detection of detector.detect({ path: path17, key, value })) {
|
|
8102
|
+
if ((detection.action ?? "replace") !== "keep") return { detector, detection };
|
|
8103
|
+
}
|
|
8104
|
+
}
|
|
8105
|
+
return void 0;
|
|
8106
|
+
}
|
|
7813
8107
|
#redactValue(value, key, path17, depth, state) {
|
|
7814
8108
|
if (depth > this.#maxDepth) {
|
|
7815
8109
|
this.#recordFinding(
|
|
@@ -7828,6 +8122,43 @@ var Redactor2 = class {
|
|
|
7828
8122
|
return applyRule(rule, value, this.#replacement);
|
|
7829
8123
|
}
|
|
7830
8124
|
}
|
|
8125
|
+
if (typeof value === "string" && looksLikeUrlForRedaction2(value)) {
|
|
8126
|
+
const url = redactUrlString2(value, {
|
|
8127
|
+
sensitiveKeys: this.#sensitiveKeys,
|
|
8128
|
+
isSensitiveValue: (candidate) => this.#detect(candidate, key, path17) !== void 0,
|
|
8129
|
+
replacement: this.#replacement,
|
|
8130
|
+
maskPathIds: this.#profile !== "local"
|
|
8131
|
+
});
|
|
8132
|
+
if (url.value !== value) {
|
|
8133
|
+
this.#recordFinding(
|
|
8134
|
+
state,
|
|
8135
|
+
makeFinding(
|
|
8136
|
+
path17,
|
|
8137
|
+
url.credentialRedacted ? "value.urlCredential" : "value.urlIdentifier",
|
|
8138
|
+
"replace",
|
|
8139
|
+
"value",
|
|
8140
|
+
url.credentialRedacted ? "error" : "warning"
|
|
8141
|
+
)
|
|
8142
|
+
);
|
|
8143
|
+
const residual = this.#detect(
|
|
8144
|
+
url.value.split(this.#replacement).join(""),
|
|
8145
|
+
key,
|
|
8146
|
+
path17
|
|
8147
|
+
);
|
|
8148
|
+
if (residual === void 0) return url.value;
|
|
8149
|
+
this.#recordFinding(
|
|
8150
|
+
state,
|
|
8151
|
+
makeFinding(
|
|
8152
|
+
path17,
|
|
8153
|
+
residual.detector.id,
|
|
8154
|
+
"replace",
|
|
8155
|
+
residual.detection.matchKind ?? residual.detector.matchKind ?? "custom",
|
|
8156
|
+
residual.detection.severity ?? residual.detector.severity ?? "warning"
|
|
8157
|
+
)
|
|
8158
|
+
);
|
|
8159
|
+
return this.#replacement;
|
|
8160
|
+
}
|
|
8161
|
+
}
|
|
7831
8162
|
for (const detector of this.#detectors) {
|
|
7832
8163
|
const detections = detector.detect({ path: path17, key, value });
|
|
7833
8164
|
for (const detection of detections) {
|