@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 +46 -2
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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.
|
|
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
|