@synkro-sh/cli 1.6.69 → 1.6.70
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 +50 -2
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -6425,6 +6425,50 @@ function loadMcpJwt(): string {
|
|
|
6425
6425
|
try { return readFileSync(join(HOME, '.synkro', '.mcp-jwt'), 'utf-8').trim(); } catch { return ''; }
|
|
6426
6426
|
}
|
|
6427
6427
|
|
|
6428
|
+
let _cfgCache: Record<string, string> | null = null;
|
|
6429
|
+
function cfgVal(key: string): string {
|
|
6430
|
+
if (process.env[key]) return process.env[key] as string;
|
|
6431
|
+
if (!_cfgCache) {
|
|
6432
|
+
_cfgCache = {};
|
|
6433
|
+
try {
|
|
6434
|
+
const txt = readFileSync(join(HOME, '.synkro', 'config.env'), 'utf-8');
|
|
6435
|
+
for (const line of txt.split('\n')) {
|
|
6436
|
+
const mm = line.match(/^([A-Z0-9_]+)=['"]?(.*?)['"]?\s*$/);
|
|
6437
|
+
if (mm) _cfgCache[mm[1]] = mm[2];
|
|
6438
|
+
}
|
|
6439
|
+
} catch {}
|
|
6440
|
+
}
|
|
6441
|
+
return _cfgCache[key] || '';
|
|
6442
|
+
}
|
|
6443
|
+
function deployIsCloud(): boolean { return cfgVal('SYNKRO_DEPLOY_LOCATION') === 'cloud'; }
|
|
6444
|
+
|
|
6445
|
+
// Cloud MCP gate: in cloud mode the local server (:18931) isn't running, so the
|
|
6446
|
+
// gate asks the org policy directly (api /api/mcp/gate, authed by .mcp-jwt).
|
|
6447
|
+
// Fail-open by contract — any error or non-block verdict allows the call.
|
|
6448
|
+
async function cloudMcpGate(payload: any, harness: string): Promise<string> {
|
|
6449
|
+
try {
|
|
6450
|
+
const toolName = String(payload.tool_name || payload.tool || '');
|
|
6451
|
+
const parts = toolName.split('__');
|
|
6452
|
+
const server = (parts.length >= 3 && parts[0] === 'mcp') ? parts[1] : '';
|
|
6453
|
+
if (!server) return failOpen(harness);
|
|
6454
|
+
const base = (cfgVal('SYNKRO_GATEWAY_URL') || 'https://api.synkro.sh').replace(/\/+$/, '');
|
|
6455
|
+
const resp = await fetch(base + '/api/mcp/gate', {
|
|
6456
|
+
method: 'POST',
|
|
6457
|
+
headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + loadMcpJwt() },
|
|
6458
|
+
body: JSON.stringify({ server: server, tool: parts.slice(2).join('__') }),
|
|
6459
|
+
signal: AbortSignal.timeout(5000),
|
|
6460
|
+
});
|
|
6461
|
+
if (!resp.ok) return failOpen(harness);
|
|
6462
|
+
const d = await resp.json() as any;
|
|
6463
|
+
if (d && d.decision === 'block') {
|
|
6464
|
+
const reason = String(d.reason || ('MCP server "' + server + '" blocked by policy'));
|
|
6465
|
+
if (harness === 'cursor') return JSON.stringify({ permission: 'deny', user_message: reason });
|
|
6466
|
+
return JSON.stringify({ systemMessage: '[synkro:cloud:mcp] ' + reason, hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason, additionalContext: reason } });
|
|
6467
|
+
}
|
|
6468
|
+
return failOpen(harness);
|
|
6469
|
+
} catch { return failOpen(harness); }
|
|
6470
|
+
}
|
|
6471
|
+
|
|
6428
6472
|
async function readStdin(): Promise<string> {
|
|
6429
6473
|
const chunks: Buffer[] = [];
|
|
6430
6474
|
for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -6484,6 +6528,10 @@ export async function runStub(surface: string, opts: StubOpts = {}): Promise<voi
|
|
|
6484
6528
|
if (!input.trim()) { out(failOpen(harness)); return; }
|
|
6485
6529
|
const payload = JSON.parse(input);
|
|
6486
6530
|
|
|
6531
|
+
// Cloud MCP enforcement: the gate can't reach the local server, so decide
|
|
6532
|
+
// against the org policy directly. Fail-open inside cloudMcpGate.
|
|
6533
|
+
if (surface === 'mcp-gate' && deployIsCloud()) { out(await cloudMcpGate(payload, harness)); return; }
|
|
6534
|
+
|
|
6487
6535
|
const workspaceRoots = Array.isArray(payload.workspace_roots) ? payload.workspace_roots : [];
|
|
6488
6536
|
const cwd = (typeof payload.cwd === 'string' && payload.cwd) || workspaceRoots[0] || '';
|
|
6489
6537
|
const sessionId = String(payload.session_id || payload.conversation_id || '');
|
|
@@ -10336,7 +10384,7 @@ function writeConfigEnv(opts) {
|
|
|
10336
10384
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
10337
10385
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
10338
10386
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
10339
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.6.
|
|
10387
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.6.70")}`
|
|
10340
10388
|
];
|
|
10341
10389
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
10342
10390
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -13930,7 +13978,7 @@ var args = process.argv.slice(2);
|
|
|
13930
13978
|
var cmd = args[0] || "";
|
|
13931
13979
|
var subArgs = args.slice(1);
|
|
13932
13980
|
function printVersion() {
|
|
13933
|
-
console.log("1.6.
|
|
13981
|
+
console.log("1.6.70");
|
|
13934
13982
|
}
|
|
13935
13983
|
function printHelp2() {
|
|
13936
13984
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|