@synkro-sh/cli 1.5.3 → 1.5.4
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 +59 -3
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -2849,6 +2849,59 @@ async function main() {
|
|
|
2849
2849
|
const cmdShort = command.slice(0, 80);
|
|
2850
2850
|
log('bashGuard checking: ' + cmdShort);
|
|
2851
2851
|
|
|
2852
|
+
// ─── Hook-side short-circuit for safe in-repo reads ───
|
|
2853
|
+
// The judge primer already deterministically allows these, but the round
|
|
2854
|
+
// trip + batch queue still costs 1–25s per call. Skipping the grade for
|
|
2855
|
+
// unambiguously read-only operations removes that latency for ~half of
|
|
2856
|
+
// typical commands (cat/grep/git status/ls/etc.) and unblocks the worker
|
|
2857
|
+
// pool to grade the operations that actually need judgment.
|
|
2858
|
+
function isSafeInRepoRead(tName: string, cmd: string): boolean {
|
|
2859
|
+
// CC's native read tools are inherently safe.
|
|
2860
|
+
if (tName === 'Read' || tName === 'Grep' || tName === 'Glob') return true;
|
|
2861
|
+
if (tName !== 'Bash' && tName !== 'Shell' && tName !== 'terminal' &&
|
|
2862
|
+
tName !== 'run_terminal_cmd' && tName !== 'execute_command') return false;
|
|
2863
|
+
// Reject any shell metacharacter that could turn a "read" into a write
|
|
2864
|
+
// or chain to an unsafe consumer: redirects, pipes, sequencing, command
|
|
2865
|
+
// substitution, sudo/su.
|
|
2866
|
+
if (/[>;&|\\\`]|\\$\\(|<<|\\bsudo\\b|\\bsu\\b|\\brm\\b|\\bmv\\b|\\bcp\\b|\\bchmod\\b|\\bchown\\b|\\btee\\b|\\bsed\\s+-i\\b|\\bkill\\b/.test(cmd)) return false;
|
|
2867
|
+
const SAFE_VERBS = new Set([
|
|
2868
|
+
'cat','head','tail','less','more','grep','egrep','fgrep','rg','ag',
|
|
2869
|
+
'find','fd','ls','wc','cmp','diff','file','stat','which','whereis','type',
|
|
2870
|
+
'pwd','whoami','id','date','echo','printf','env','true','false',
|
|
2871
|
+
'jq','yq','awk','sort','uniq','cut','tr','xxd','hexdump','od','column',
|
|
2872
|
+
'node','npm','pnpm','yarn','bun','python','python3','ruby','go','rustc','cargo',
|
|
2873
|
+
'git',
|
|
2874
|
+
]);
|
|
2875
|
+
const tokens = cmd.trim().split(/\\s+/);
|
|
2876
|
+
const verb = tokens[0] || '';
|
|
2877
|
+
if (!SAFE_VERBS.has(verb)) return false;
|
|
2878
|
+
// For multi-mode tools, only allow read subcommands / version flags.
|
|
2879
|
+
if (verb === 'git') {
|
|
2880
|
+
const SAFE_GIT = new Set(['log','show','diff','blame','status','branch','tag','remote','config','rev-parse','ls-files','ls-tree','cat-file','shortlog','reflog','describe','symbolic-ref']);
|
|
2881
|
+
const sub = tokens[1] || '';
|
|
2882
|
+
return SAFE_GIT.has(sub);
|
|
2883
|
+
}
|
|
2884
|
+
if (['npm','pnpm','yarn','bun','cargo','go'].includes(verb)) {
|
|
2885
|
+
// Only allow plain version/info/list/why probes — block install/add/update/run/exec.
|
|
2886
|
+
const sub = tokens[1] || '';
|
|
2887
|
+
const SAFE_PKG = new Set(['--version','-v','version','list','ls','why','view','show','info','outdated','-h','--help','help']);
|
|
2888
|
+
return SAFE_PKG.has(sub);
|
|
2889
|
+
}
|
|
2890
|
+
if (['node','python','python3','ruby','rustc'].includes(verb)) {
|
|
2891
|
+
const sub = tokens[1] || '';
|
|
2892
|
+
return sub === '--version' || sub === '-v' || sub === '-V';
|
|
2893
|
+
}
|
|
2894
|
+
// sed without -i flag is read-only by definition; we already excluded
|
|
2895
|
+
// sed -i above. Anything else with a SAFE_VERB and no metachars is fine.
|
|
2896
|
+
return true;
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
if (isSafeInRepoRead(toolName, command)) {
|
|
2900
|
+
log('bashGuard ' + cmdShort + ' → instant allow (safe in-repo read)');
|
|
2901
|
+
outputJson({ hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: 'Synkro: safe in-repo read, deterministic allow.' } });
|
|
2902
|
+
return;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2852
2905
|
let jwt = loadJwt();
|
|
2853
2906
|
if (!jwt) { outputEmpty(); return; }
|
|
2854
2907
|
jwt = await ensureFreshJwt(jwt);
|
|
@@ -5570,6 +5623,9 @@ async function dockerInstall(opts = {}) {
|
|
|
5570
5623
|
`${CLAUDE_HOST_STATE_DIR}:/data/claude-host-state:ro`,
|
|
5571
5624
|
"-e",
|
|
5572
5625
|
`WORKERS_PER_POOL=${workers}`,
|
|
5626
|
+
// Pass through the batch-size lever if the operator set it. Defaults
|
|
5627
|
+
// inside the container to 5; clamped to [1, 20] by synkro-server.ts.
|
|
5628
|
+
...process.env.SYNKRO_MAX_BATCH_SIZE ? ["-e", `SYNKRO_MAX_BATCH_SIZE=${process.env.SYNKRO_MAX_BATCH_SIZE}`] : [],
|
|
5573
5629
|
image
|
|
5574
5630
|
];
|
|
5575
5631
|
const run = spawnSync2("docker", args2, { encoding: "utf-8", stdio: "inherit", timeout: 6e4 });
|
|
@@ -5796,7 +5852,7 @@ function writeConfigEnv(opts) {
|
|
|
5796
5852
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
5797
5853
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
5798
5854
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
5799
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.5.
|
|
5855
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.5.4")}`
|
|
5800
5856
|
];
|
|
5801
5857
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
5802
5858
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -6203,7 +6259,7 @@ async function installCommand(opts = {}) {
|
|
|
6203
6259
|
process.exit(1);
|
|
6204
6260
|
}
|
|
6205
6261
|
console.log("Installing Synkro server container...");
|
|
6206
|
-
const workersPerPool = parseInt(process.env.SYNKRO_WORKERS_PER_POOL || "
|
|
6262
|
+
const workersPerPool = parseInt(process.env.SYNKRO_WORKERS_PER_POOL || "8", 10);
|
|
6207
6263
|
const { image, hostMcpPort, hostGraderPort, hostCwePort } = await dockerInstall({ workersPerPool });
|
|
6208
6264
|
console.log(` \u2713 pulled ${image}`);
|
|
6209
6265
|
console.log(` container started \u2014 MCP=${hostMcpPort} general=${hostGraderPort} CWE=${hostCwePort}`);
|
|
@@ -7186,7 +7242,7 @@ var args = process.argv.slice(2);
|
|
|
7186
7242
|
var cmd = args[0] || "";
|
|
7187
7243
|
var subArgs = args.slice(1);
|
|
7188
7244
|
function printVersion() {
|
|
7189
|
-
console.log("1.5.
|
|
7245
|
+
console.log("1.5.4");
|
|
7190
7246
|
}
|
|
7191
7247
|
function printHelp() {
|
|
7192
7248
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|