@synkro-sh/cli 1.6.90 → 1.6.91

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/bootstrap.js CHANGED
@@ -2218,6 +2218,44 @@ function isPlaceholderSecret(v: string): boolean {
2218
2218
  const tail = v.replace(/^(sk-ant-|[rs]k_(?:live|test)_|sk-|AKIA|gh[posru]_|AIza|xox[baprs]-|Bearer[ ]+)/, '');
2219
2219
  return /^(x+|0+|a+|placeholder|example|changeme|your[-_a-z0-9]*|dummy|test|fake|redacted|sample)$/i.test(tail);
2220
2220
  }
2221
+ // \u2500\u2500 Opaque-secret heuristic (catches the FORMAT-LESS tail the regex can't) \u2500\u2500
2222
+ // A high-entropy value sitting in a SECRET CONTEXT \u2014 assigned to a secret-named
2223
+ // variable, in an auth header, or as a connection-string password. Local +
2224
+ // deterministic, no model. Char-class regexes only (template-literal backslash safe).
2225
+ function shannonEntropy(s: string): number {
2226
+ const m: Record<string, number> = {};
2227
+ for (const ch of s) m[ch] = (m[ch] || 0) + 1;
2228
+ let h = 0;
2229
+ for (const k in m) { const p = m[k] / s.length; h -= p * Math.log2(p); }
2230
+ return h;
2231
+ }
2232
+ function looksOpaqueSecret(v: string): boolean {
2233
+ if (v.length < 16) return false;
2234
+ if (/[$<>{}]/.test(v)) return false; // env ref / placeholder
2235
+ if (/^[0-9a-f]{32,}$/i.test(v)) return false; // hex hash / sha
2236
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v)) return false; // uuid
2237
+ if (!(/[a-zA-Z]/.test(v) && /[0-9]/.test(v))) return false; // real tokens mix letters+digits
2238
+ return shannonEntropy(v) >= 3.2;
2239
+ }
2240
+ const OPAQUE_CTX_PATTERNS: RegExp[] = [
2241
+ /[A-Za-z_][A-Za-z0-9_-]*(?:secret|token|key|password|passwd|api[_-]?key|auth|credential)[A-Za-z0-9_-]*[ ]*[=:][ ]*["']?([^ "'&|;]+)/gi,
2242
+ /(?:authorization|x-api-key|x-auth-token|api-key)[ ]*:[ ]*(?:bearer[ ]+)?([^ "']+)/gi,
2243
+ /[a-z][a-z0-9+.-]*:[/][/][^:/@ ]+:([^@/ ]+)@/gi,
2244
+ ];
2245
+ export function detectOpaqueSecrets(text: string): SecretHit[] {
2246
+ if (!text) return [];
2247
+ const hits: SecretHit[] = [];
2248
+ const seen = new Set<string>();
2249
+ for (const re of OPAQUE_CTX_PATTERNS) {
2250
+ re.lastIndex = 0;
2251
+ let m: RegExpExecArray | null;
2252
+ while ((m = re.exec(text)) !== null) {
2253
+ const v = m[1];
2254
+ if (v && !seen.has(v) && looksOpaqueSecret(v)) { seen.add(v); hits.push({ type: 'opaque-secret', value: v }); }
2255
+ }
2256
+ }
2257
+ return hits;
2258
+ }
2221
2259
  export function detectHardSecrets(text: string): SecretHit[] {
2222
2260
  if (!text) return [];
2223
2261
  const hits: SecretHit[] = [];
@@ -2232,6 +2270,10 @@ export function detectHardSecrets(text: string): SecretHit[] {
2232
2270
  hits.push({ type, value: v });
2233
2271
  }
2234
2272
  }
2273
+ // Union the format-less opaque-secret tail (entropy + secret context).
2274
+ for (const h of detectOpaqueSecrets(text)) {
2275
+ if (!seen.has(h.value)) { seen.add(h.value); hits.push(h); }
2276
+ }
2235
2277
  return hits;
2236
2278
  }
2237
2279
  // Shape-preserving redaction for persist/log/grade boundaries: the reader still
@@ -2247,6 +2289,8 @@ export function scrubSecrets(text: string): string {
2247
2289
  if (/[$<>{}]/.test(val)) return full;
2248
2290
  return pfx + '<redacted:credential>';
2249
2291
  });
2292
+ // Format-less opaque secrets (entropy + secret context) the patterns above miss.
2293
+ for (const h of detectOpaqueSecrets(out)) out = out.split(h.value).join('<redacted:opaque-secret>');
2250
2294
  return out;
2251
2295
  }
2252
2296
  function guessEnvName(type: string, i: number): string {
@@ -11164,7 +11208,7 @@ function writeConfigEnv(opts) {
11164
11208
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
11165
11209
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
11166
11210
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
11167
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.90")}`
11211
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.91")}`
11168
11212
  ];
11169
11213
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
11170
11214
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -15207,7 +15251,7 @@ var args = process.argv.slice(2);
15207
15251
  var cmd = args[0] || "";
15208
15252
  var subArgs = args.slice(1);
15209
15253
  function printVersion() {
15210
- console.log("1.6.90");
15254
+ console.log("1.6.91");
15211
15255
  }
15212
15256
  function printHelp2() {
15213
15257
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents