@bli-cockpit/telemetry-core 0.1.17 → 0.1.18
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/secret-guards.js +54 -2
- package/package.json +1 -1
package/dist/secret-guards.js
CHANGED
|
@@ -225,7 +225,30 @@ export function redactSecretLikeContent(value, options = {}) {
|
|
|
225
225
|
});
|
|
226
226
|
return { redacted: true, text, metadata };
|
|
227
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Every region the detector considers a secret, redacted — precisely where a
|
|
230
|
+
* rule can pinpoint the value, coarsely where none can.
|
|
231
|
+
*
|
|
232
|
+
* `containsSecretLikeContent` and `SECRET_REDACTION_RULES` are two lists that
|
|
233
|
+
* have to agree, and nothing used to make them. When the detector matched and
|
|
234
|
+
* no rule produced a range, `redactSecretLikeContent` reported
|
|
235
|
+
* `redacted: false`, and the caller dropped the entire session file
|
|
236
|
+
* (`secret_like_content_guard`). Drift between the lists cost whole sessions:
|
|
237
|
+
* 78 fleet-wide as of 2026-08-14, 3 of Viet's 17 Claude sessions.
|
|
238
|
+
*
|
|
239
|
+
* The two lists can still drift — regexes are like that — but drift now costs
|
|
240
|
+
* precision instead of evidence. A detector hit with no matching rule redacts
|
|
241
|
+
* the whole matched span, so `redactSecretLikeContent` always reports the
|
|
242
|
+
* redaction it performed and the transcript survives with the value removed.
|
|
243
|
+
*/
|
|
228
244
|
function findSecretRedactionMatches(value) {
|
|
245
|
+
const accepted = acceptNonOverlapping(secretRuleCandidates(value));
|
|
246
|
+
const uncovered = detectorFallbackCandidates(value).filter((candidate) => !overlapsAny(candidate, accepted));
|
|
247
|
+
if (uncovered.length === 0)
|
|
248
|
+
return accepted;
|
|
249
|
+
return acceptNonOverlapping([...accepted, ...uncovered]);
|
|
250
|
+
}
|
|
251
|
+
function secretRuleCandidates(value) {
|
|
229
252
|
const candidates = [];
|
|
230
253
|
SECRET_REDACTION_RULES.forEach((rule, priority) => {
|
|
231
254
|
const pattern = cloneGlobalPattern(rule.pattern);
|
|
@@ -248,7 +271,36 @@ function findSecretRedactionMatches(value) {
|
|
|
248
271
|
});
|
|
249
272
|
}
|
|
250
273
|
});
|
|
251
|
-
candidates
|
|
274
|
+
return candidates;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Ranked below every real rule, so a rule that can name the credential always
|
|
278
|
+
* wins and the coarse span is only used where nothing else reached.
|
|
279
|
+
*/
|
|
280
|
+
function detectorFallbackCandidates(value) {
|
|
281
|
+
const candidates = [];
|
|
282
|
+
const basePriority = SECRET_REDACTION_RULES.length;
|
|
283
|
+
SECRET_LIKE_CONTENT_PATTERNS.forEach((pattern, offset) => {
|
|
284
|
+
for (const match of value.matchAll(cloneGlobalPattern(pattern))) {
|
|
285
|
+
const fullMatch = match[0];
|
|
286
|
+
const matchIndex = match.index;
|
|
287
|
+
if (!fullMatch || matchIndex === undefined)
|
|
288
|
+
continue;
|
|
289
|
+
candidates.push({
|
|
290
|
+
start: matchIndex,
|
|
291
|
+
end: matchIndex + fullMatch.length,
|
|
292
|
+
ruleId: "unnamed_secret_shape",
|
|
293
|
+
priority: basePriority + offset,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
return candidates;
|
|
298
|
+
}
|
|
299
|
+
function overlapsAny(candidate, accepted) {
|
|
300
|
+
return accepted.some((other) => candidate.start < other.end && other.start < candidate.end);
|
|
301
|
+
}
|
|
302
|
+
function acceptNonOverlapping(candidates) {
|
|
303
|
+
const ordered = [...candidates].sort((a, b) => {
|
|
252
304
|
if (a.start !== b.start)
|
|
253
305
|
return a.start - b.start;
|
|
254
306
|
if (a.priority !== b.priority)
|
|
@@ -257,7 +309,7 @@ function findSecretRedactionMatches(value) {
|
|
|
257
309
|
});
|
|
258
310
|
const accepted = [];
|
|
259
311
|
let lastEnd = -1;
|
|
260
|
-
for (const candidate of
|
|
312
|
+
for (const candidate of ordered) {
|
|
261
313
|
if (candidate.start < lastEnd)
|
|
262
314
|
continue;
|
|
263
315
|
accepted.push(candidate);
|