@cortexkit/opencode-magic-context 0.27.0 → 0.27.1
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/index.js
CHANGED
|
@@ -190163,6 +190163,12 @@ function redactionTypeForKey(key) {
|
|
|
190163
190163
|
const suffix = normalized.split(".").filter(Boolean).at(-1) ?? normalized;
|
|
190164
190164
|
return suffix || "secret";
|
|
190165
190165
|
}
|
|
190166
|
+
function isNonSecretScalarValue(value) {
|
|
190167
|
+
const v = value.trim();
|
|
190168
|
+
if (v === "true" || v === "false" || v === "null" || v === "undefined")
|
|
190169
|
+
return true;
|
|
190170
|
+
return /^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(v);
|
|
190171
|
+
}
|
|
190166
190172
|
var SECRET_QUALIFIERS = new Set([
|
|
190167
190173
|
"api",
|
|
190168
190174
|
"access",
|
|
@@ -190242,11 +190248,11 @@ var SECRET_TEXT_PATTERNS = [
|
|
|
190242
190248
|
},
|
|
190243
190249
|
{
|
|
190244
190250
|
pattern: /(["'])([^"']*(?:key|token|secret|password|auth|bearer|credential)[^"']*)\1(\s*:\s*)(["'])([^"']*)\4/gi,
|
|
190245
|
-
replacement: (
|
|
190251
|
+
replacement: (full, quote, key, separator, valueQuote, value) => isNonSecretScalarValue(value) ? full : `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`
|
|
190246
190252
|
},
|
|
190247
190253
|
{
|
|
190248
190254
|
pattern: /\b([A-Za-z0-9_.-]*(?:key|token|secret|password|auth|bearer|credential)[A-Za-z0-9_.-]*)\s*=\s*([^\s'"`]+)/gi,
|
|
190249
|
-
replacement: (
|
|
190255
|
+
replacement: (full, key, value) => isNonSecretScalarValue(value) ? full : `${key}=<REDACTED:${redactionTypeForKey(key)}>`
|
|
190250
190256
|
}
|
|
190251
190257
|
];
|
|
190252
190258
|
function redactSecretText(value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../src/shared/redaction.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../src/shared/redaction.ts"],"names":[],"mappings":"AAyEA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAkChD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcxD;AA0ED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAatD;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D;AAsBD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOlE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,OAAO,CAkBnF"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
import { describe, expect, test } from "bun:test";
|
|
4
4
|
|
|
5
|
-
import { hasShareabilitySensitiveText } from "./redaction";
|
|
5
|
+
import { hasShareabilitySensitiveText, redactSecretText } from "./redaction";
|
|
6
|
+
|
|
7
|
+
describe("redactSecretText — token counts and scalar diagnostics stay visible", () => {
|
|
8
|
+
test("keeps numeric/boolean values whose key merely contains a secret word", () => {
|
|
9
|
+
// These log shapes are counts/flags, not secrets, so they must stay readable.
|
|
10
|
+
expect(redactSecretText("tokens.input=45000 cache.read=0 cache.write=0")).toBe(
|
|
11
|
+
"tokens.input=45000 cache.read=0 cache.write=0",
|
|
12
|
+
);
|
|
13
|
+
expect(redactSecretText("hasUsageTokens=true")).toBe("hasUsageTokens=true");
|
|
14
|
+
expect(redactSecretText("totalInputTokens=132000")).toBe("totalInputTokens=132000");
|
|
15
|
+
expect(redactSecretText("max_tokens=4096")).toBe("max_tokens=4096");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("keeps quoted numeric values matched only on the key word", () => {
|
|
19
|
+
expect(redactSecretText('"max_tokens": "4096"')).toBe('"max_tokens": "4096"');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("still redacts real secret string values", () => {
|
|
23
|
+
// High-entropy / non-scalar values must always be redacted; only bare
|
|
24
|
+
// numeric/boolean scalars are exempt from the key-based match.
|
|
25
|
+
expect(redactSecretText("api_key=sk-abc123XYZsecretvalue")).toContain("<REDACTED:");
|
|
26
|
+
expect(redactSecretText("api_key=sk-abc123XYZsecretvalue")).not.toContain(
|
|
27
|
+
"sk-abc123XYZsecretvalue",
|
|
28
|
+
);
|
|
29
|
+
expect(redactSecretText('"auth_token": "tok_live_9f8e7d6c5b"')).toContain("<REDACTED:");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("value-shaped secret patterns still fire independent of key name", () => {
|
|
33
|
+
// A bearer/JWT value is caught by its own pattern even if its key is bland.
|
|
34
|
+
expect(redactSecretText("Authorization: Bearer abc123def456ghi789")).toContain(
|
|
35
|
+
"<REDACTED:bearer>",
|
|
36
|
+
);
|
|
37
|
+
expect(redactSecretText("blob=eyJhbGciOi.eyJzdWIiOiIx.SflKxwRJSMeKKF2QT4")).toContain(
|
|
38
|
+
"<JWT_REDACTED>",
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
6
42
|
|
|
7
43
|
describe("hasShareabilitySensitiveText", () => {
|
|
8
44
|
test("safe project facts are shareable", () => {
|
package/src/shared/redaction.ts
CHANGED
|
@@ -33,6 +33,22 @@ function redactionTypeForKey(key: string): string {
|
|
|
33
33
|
return suffix || "secret";
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// A bare number / boolean / null is never a secret — an API key, bearer token,
|
|
37
|
+
// password, or credential is always a high-entropy string. So when a key-based
|
|
38
|
+
// pattern (the `name=value` / `"name":"value"` forms below) matches purely on
|
|
39
|
+
// the KEY containing a word like "token", but the VALUE is numeric/boolean, it's
|
|
40
|
+
// a count or flag, not a secret. These must stay readable in logs:
|
|
41
|
+
// `tokens.input=45000`, `hasUsageTokens=true`, `max_tokens=4096` are diagnostics,
|
|
42
|
+
// not credentials. (High-entropy secret VALUES are still caught by the
|
|
43
|
+
// value-shaped patterns above — bearer, JWT, AKIA, gh*_, etc. — independent of
|
|
44
|
+
// the key name, so relaxing the key-based match for scalars loses no coverage.)
|
|
45
|
+
function isNonSecretScalarValue(value: string): boolean {
|
|
46
|
+
const v = value.trim();
|
|
47
|
+
if (v === "true" || v === "false" || v === "null" || v === "undefined") return true;
|
|
48
|
+
// Integer or decimal, optional sign/exponent — token counts, ports, sizes.
|
|
49
|
+
return /^[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(v);
|
|
50
|
+
}
|
|
51
|
+
|
|
36
52
|
const SECRET_QUALIFIERS = new Set([
|
|
37
53
|
"api",
|
|
38
54
|
"access",
|
|
@@ -155,19 +171,27 @@ const SECRET_TEXT_PATTERNS: Array<{
|
|
|
155
171
|
pattern:
|
|
156
172
|
/(["'])([^"']*(?:key|token|secret|password|auth|bearer|credential)[^"']*)\1(\s*:\s*)(["'])([^"']*)\4/gi,
|
|
157
173
|
replacement: (
|
|
158
|
-
|
|
174
|
+
full: string,
|
|
159
175
|
quote: string,
|
|
160
176
|
key: string,
|
|
161
177
|
separator: string,
|
|
162
178
|
valueQuote: string,
|
|
179
|
+
value: string,
|
|
163
180
|
) =>
|
|
164
|
-
|
|
181
|
+
// A numeric/boolean value matched only because the KEY contains a
|
|
182
|
+
// secret word (e.g. "max_tokens": "4096") is a count, not a secret.
|
|
183
|
+
isNonSecretScalarValue(value)
|
|
184
|
+
? full
|
|
185
|
+
: `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`,
|
|
165
186
|
},
|
|
166
187
|
{
|
|
167
188
|
pattern:
|
|
168
189
|
/\b([A-Za-z0-9_.-]*(?:key|token|secret|password|auth|bearer|credential)[A-Za-z0-9_.-]*)\s*=\s*([^\s'"`]+)/gi,
|
|
169
|
-
replacement: (
|
|
170
|
-
|
|
190
|
+
replacement: (full: string, key: string, value: string) =>
|
|
191
|
+
// tokens.input=45000 / hasUsageTokens=true are diagnostics, not
|
|
192
|
+
// secrets — keep them readable. Real secret values are still caught
|
|
193
|
+
// by the value-shaped patterns above.
|
|
194
|
+
isNonSecretScalarValue(value) ? full : `${key}=<REDACTED:${redactionTypeForKey(key)}>`,
|
|
171
195
|
},
|
|
172
196
|
];
|
|
173
197
|
|