@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: (_full, quote, key, separator, valueQuote) => `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`
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: (_full, key) => `${key}=<REDACTED:${redactionTypeForKey(key)}>`
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":"AAyDA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAkChD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcxD;AAkED,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"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",
@@ -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", () => {
@@ -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
- _full: string,
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
- `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`,
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: (_full: string, key: string) =>
170
- `${key}=<REDACTED:${redactionTypeForKey(key)}>`,
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