@synkro-sh/cli 1.6.92 → 1.6.93

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
@@ -5796,35 +5796,14 @@ async function main() {
5796
5796
  return;
5797
5797
  }
5798
5798
 
5799
- if (isSafeInRepoRead(toolName, command, cwd)) {
5800
- log('bashGuard ' + cmdShort + ' → instant allow (safe in-repo read)');
5801
- appendLocalTelemetry({
5802
- capture_type: 'local_verdict',
5803
- verdict: 'pass',
5804
- hook_type: 'bash',
5805
- category: 'safe_read',
5806
- tool_name: toolName,
5807
- command: command.slice(0, 200),
5808
- session_id: sessionId,
5809
- repo: gitRepo || cwd,
5810
- cc_model: transcript.ccModel,
5811
- reasoning: 'Safe in-repo read — auto-allowed without an LLM grade.',
5812
- });
5813
- outputJson({
5814
- systemMessage: tagStr + ' bashGuard → pass: safe in-repo read',
5815
- hookSpecificOutput: {
5816
- hookEventName: 'PreToolUse',
5817
- additionalContext: tagStr + ' bashGuard pass: safe in-repo read.',
5818
- },
5819
- });
5820
- return;
5821
- }
5822
-
5823
5799
  // ─── Secret firewall: BLOCK a literal credential in the command BEFORE it runs
5824
5800
  // or reaches the grader — the value never lands in a file, shell history, OR the
5825
5801
  // LLM provider (no leak to Anthropic/Cursor). Deterministic + local, no model
5826
5802
  // call. High-confidence formats only (a false block stops the user), and
5827
- // $VAR / placeholder refs never trip it. ───
5803
+ // $VAR / placeholder refs never trip it. MUST run BEFORE the safe-read fast-path
5804
+ // below — otherwise an echo/printf of a literal secret is treated as a safe read
5805
+ // and waved through. A genuine read carries no literal secret, so this never
5806
+ // false-blocks legitimate reads. ───
5828
5807
  const secretHits = detectHardSecrets(command);
5829
5808
  if (secretHits.length) {
5830
5809
  const types = secretHits.map(h => h.type).join(', ');
@@ -5849,6 +5828,32 @@ async function main() {
5849
5828
  return;
5850
5829
  }
5851
5830
 
5831
+ // Safe in-repo read fast-path — runs AFTER the secret firewall above so a
5832
+ // literal credential is never waved through as a "safe read".
5833
+ if (isSafeInRepoRead(toolName, command, cwd)) {
5834
+ log('bashGuard ' + cmdShort + ' → instant allow (safe in-repo read)');
5835
+ appendLocalTelemetry({
5836
+ capture_type: 'local_verdict',
5837
+ verdict: 'pass',
5838
+ hook_type: 'bash',
5839
+ category: 'safe_read',
5840
+ tool_name: toolName,
5841
+ command: command.slice(0, 200),
5842
+ session_id: sessionId,
5843
+ repo: gitRepo || cwd,
5844
+ cc_model: transcript.ccModel,
5845
+ reasoning: 'Safe in-repo read — auto-allowed without an LLM grade.',
5846
+ });
5847
+ outputJson({
5848
+ systemMessage: tagStr + ' bashGuard → pass: safe in-repo read',
5849
+ hookSpecificOutput: {
5850
+ hookEventName: 'PreToolUse',
5851
+ additionalContext: tagStr + ' bashGuard pass: safe in-repo read.',
5852
+ },
5853
+ });
5854
+ return;
5855
+ }
5856
+
5852
5857
  // ─── Install protection: install-scan runs first and owns block traces ───
5853
5858
  let scanConcern = '';
5854
5859
  let scanBlockContext = '';
@@ -6872,6 +6877,25 @@ async function main() {
6872
6877
 
6873
6878
  // Instant-allow read-only tool calls + safe in-repo bash reads \u2014 no grade,
6874
6879
  // no network. Critical under Cursor's tight 15s beforeShellExecution budget.
6880
+ // \u2500\u2500\u2500 Secret firewall: BLOCK a literal credential in the command BEFORE it runs
6881
+ // or reaches the grader \u2014 never leaks to a file, shell history, or the model
6882
+ // (Anthropic/Cursor). Local + deterministic; $VAR / placeholder refs never trip
6883
+ // it. MUST run BEFORE the safe-read fast-path below \u2014 else an echo/printf of a
6884
+ // literal secret is waved through as a "safe read". \u2500\u2500\u2500
6885
+ const secretHits = detectHardSecrets(command);
6886
+ if (secretHits.length) {
6887
+ const types = secretHits.map(h => h.type).join(', ');
6888
+ const remediation = secretRemediation(command, secretHits);
6889
+ log('bashGuard ' + cmdShort + ' \u2192 BLOCKED: literal credential (' + types + ')');
6890
+ appendLocalTelemetry({
6891
+ capture_type: 'local_verdict', verdict: 'block', hook_type: 'bash',
6892
+ category: 'secret_exposure', tool_name: toolName, command: scrubSecrets(command).slice(0, 200),
6893
+ session_id: sessionId, repo: repo || cwd, cc_model: model,
6894
+ reasoning: 'Literal credential (' + types + ') in the proposed command \u2014 blocked locally before grading; never sent to the model.',
6895
+ });
6896
+ finishWith({ permission: 'deny', user_message: '[synkro] bashGuard \u2192 BLOCKED: literal credential in command (' + types + '). Use an env var reference instead.', agent_message: remediation });
6897
+ }
6898
+
6875
6899
  if (isSafeInRepoRead(toolName, command, cwd)) {
6876
6900
  log('bashGuard ' + cmdShort + ' \u2192 instant allow (safe in-repo read)');
6877
6901
  appendLocalTelemetry({
@@ -6899,23 +6923,6 @@ async function main() {
6899
6923
  const rt = await route(config, synkroFile);
6900
6924
  const tagStr = tag(rt, config, graderPool);
6901
6925
 
6902
- // Secret firewall: BLOCK a literal credential in the command BEFORE it runs or
6903
- // reaches the grader \u2014 never leaks to a file, shell history, or the model
6904
- // (Anthropic/Cursor). Local + deterministic; $VAR / placeholder refs never trip it.
6905
- const secretHits = detectHardSecrets(command);
6906
- if (secretHits.length) {
6907
- const types = secretHits.map(h => h.type).join(', ');
6908
- const remediation = secretRemediation(command, secretHits);
6909
- log('bashGuard ' + cmdShort + ' \u2192 BLOCKED: literal credential (' + types + ')');
6910
- appendLocalTelemetry({
6911
- capture_type: 'local_verdict', verdict: 'block', hook_type: 'bash',
6912
- category: 'secret_exposure', tool_name: toolName, command: scrubSecrets(command).slice(0, 200),
6913
- session_id: sessionId, repo: repo || cwd, cc_model: model,
6914
- reasoning: 'Literal credential (' + types + ') in the proposed command \u2014 blocked locally before grading; never sent to the model.',
6915
- });
6916
- finishWith({ permission: 'deny', user_message: tagStr + ' bashGuard \u2192 BLOCKED: literal credential in command (' + types + '). Use an env var reference instead.', agent_message: remediation });
6917
- }
6918
-
6919
6926
  // Install protection \u2014 install-scan runs first and owns block traces.
6920
6927
  let scanConcern = '';
6921
6928
  let scanBlockContext = '';
@@ -11230,7 +11237,7 @@ function writeConfigEnv(opts) {
11230
11237
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
11231
11238
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
11232
11239
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
11233
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.92")}`
11240
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.93")}`
11234
11241
  ];
11235
11242
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
11236
11243
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -15295,7 +15302,7 @@ var args = process.argv.slice(2);
15295
15302
  var cmd = args[0] || "";
15296
15303
  var subArgs = args.slice(1);
15297
15304
  function printVersion() {
15298
- console.log("1.6.92");
15305
+ console.log("1.6.93");
15299
15306
  }
15300
15307
  function printHelp2() {
15301
15308
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents