@synkro-sh/cli 1.4.22 → 1.4.24
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 +83 -20
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -499,21 +499,14 @@ synkro_channel_up() {
|
|
|
499
499
|
(exec 3<>/dev/tcp/127.0.0.1/\${SYNKRO_CHANNEL_PORT:-8929}) 2>/dev/null && exec 3<&- 3>&-
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
-
# Fetch hook config
|
|
502
|
+
# Fetch hook config. Sets SYNKRO_CAPTURE_DEPTH, SYNKRO_TIER, SYNKRO_RULES.
|
|
503
503
|
synkro_load_config() {
|
|
504
|
-
local cache="$HOME/.synkro/.hook-config-cache"
|
|
505
|
-
if [ -f "$cache" ] && find "$cache" -mmin -5 2>/dev/null | grep -q .; then
|
|
506
|
-
. "$cache" 2>/dev/null
|
|
507
|
-
return
|
|
508
|
-
fi
|
|
509
504
|
local resp
|
|
510
505
|
resp=$(curl -sS "\${GATEWAY_URL}/api/v1/hook/config\${1:+?$1}" -H "Authorization: Bearer $JWT" --max-time 4 2>/dev/null || echo "")
|
|
511
506
|
if [ -z "$resp" ]; then return; fi
|
|
512
507
|
SYNKRO_CAPTURE_DEPTH=$(echo "$resp" | jq -r '.capture_depth // "local_only"' 2>/dev/null)
|
|
513
508
|
SYNKRO_TIER=$(echo "$resp" | jq -r '.tier // "standard"' 2>/dev/null)
|
|
514
509
|
SYNKRO_RULES=$(echo "$resp" | jq -c '[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id,text,severity,category,mode}]' 2>/dev/null || echo "[]")
|
|
515
|
-
# Cache the values
|
|
516
|
-
printf 'SYNKRO_CAPTURE_DEPTH="%s"\\nSYNKRO_TIER="%s"\\n' "$SYNKRO_CAPTURE_DEPTH" "$SYNKRO_TIER" > "$cache" 2>/dev/null || true
|
|
517
510
|
}
|
|
518
511
|
|
|
519
512
|
# Decide routing: "local" (grade on device) or "cloud" (POST to server)
|
|
@@ -549,13 +542,19 @@ synkro_parse_local_verdict() {
|
|
|
549
542
|
LOCAL_REASON=$(printf '%s' "$inner" | sed -nE 's|.*<reason>(.*)</reason>.*|\\1|p' | head -1)
|
|
550
543
|
[ -z "$LOCAL_REASON" ] && LOCAL_REASON=$(printf '%s' "$inner" | sed -nE 's|.*<reasoning>(.*)</reasoning>.*|\\1|p' | head -1)
|
|
551
544
|
if [ "$LOCAL_OK" = "false" ]; then
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
[ -z "$
|
|
556
|
-
|
|
557
|
-
|
|
545
|
+
LOCAL_RULE_ID=$(printf '%s' "$inner" | sed -nE 's|.*<rule_id>(.*)</rule_id>.*|\\1|p' | head -1)
|
|
546
|
+
LOCAL_SEV=$(printf '%s' "$inner" | sed -nE 's|.*<risk_level>(.*)</risk_level>.*|\\1|p' | head -1)
|
|
547
|
+
LOCAL_CAT=$(printf '%s' "$inner" | sed -nE 's|.*<category>(.*)</category>.*|\\1|p' | head -1)
|
|
548
|
+
if [ -z "$LOCAL_RULE_ID" ]; then
|
|
549
|
+
local fv
|
|
550
|
+
fv=$(printf '%s' "$inner" | awk -v RS='</violation>' '/<violation>/{print; exit}')
|
|
551
|
+
LOCAL_RULE_ID=$(printf '%s' "$fv" | sed -nE 's|.*<rule_id>(.*)</rule_id>.*|\\1|p' | head -1)
|
|
552
|
+
[ -z "$LOCAL_REASON" ] && LOCAL_REASON=$(printf '%s' "$fv" | sed -nE 's|.*<reason>(.*)</reason>.*|\\1|p' | head -1)
|
|
553
|
+
[ -z "$LOCAL_SEV" ] && LOCAL_SEV=$(printf '%s' "$fv" | sed -nE 's|.*<severity>(.*)</severity>.*|\\1|p' | head -1)
|
|
554
|
+
[ -z "$LOCAL_CAT" ] && LOCAL_CAT=$(printf '%s' "$fv" | sed -nE 's|.*<category>(.*)</category>.*|\\1|p' | head -1)
|
|
555
|
+
fi
|
|
558
556
|
LOCAL_SEV="\${LOCAL_SEV:-high}"; LOCAL_CAT="\${LOCAL_CAT:-policy_violation}"
|
|
557
|
+
[ -z "$LOCAL_RULE_ID" ] && LOCAL_RULE_ID=$(printf '%s' "$LOCAL_REASON" | grep -oE '[Rr][0-9]{3}' | head -1)
|
|
559
558
|
fi
|
|
560
559
|
}
|
|
561
560
|
|
|
@@ -586,6 +585,37 @@ synkro_rule_mode() {
|
|
|
586
585
|
echo "$m"
|
|
587
586
|
}
|
|
588
587
|
|
|
588
|
+
SYNKRO_CONSENT_FILE="$HOME/.synkro/.local-consent"
|
|
589
|
+
|
|
590
|
+
synkro_consent_grant() {
|
|
591
|
+
local sid="$1" hash="$2"
|
|
592
|
+
printf '%s\\t%s\\tactive\\n' "$sid" "$hash" >> "$SYNKRO_CONSENT_FILE" 2>/dev/null || true
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
synkro_consent_has_active() {
|
|
596
|
+
local sid="$1" hash="$2"
|
|
597
|
+
grep -q "^$sid\\\\t$hash\\\\tactive$" "$SYNKRO_CONSENT_FILE" 2>/dev/null
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
synkro_consent_consume() {
|
|
601
|
+
local sid="$1" hash="$2"
|
|
602
|
+
[ ! -f "$SYNKRO_CONSENT_FILE" ] && return
|
|
603
|
+
local tmp="\${SYNKRO_CONSENT_FILE}.tmp"
|
|
604
|
+
sed "s/^$sid\\\\t$hash\\\\tactive$/$sid\\t$hash\\tconsumed/" "$SYNKRO_CONSENT_FILE" > "$tmp" 2>/dev/null && mv "$tmp" "$SYNKRO_CONSENT_FILE" 2>/dev/null || true
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
synkro_consent_has_consumed() {
|
|
608
|
+
local sid="$1" hash="$2"
|
|
609
|
+
grep -q "^$sid\\\\t$hash\\\\tconsumed$" "$SYNKRO_CONSENT_FILE" 2>/dev/null
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
synkro_consent_clear_consumed() {
|
|
613
|
+
local sid="$1" hash="$2"
|
|
614
|
+
[ ! -f "$SYNKRO_CONSENT_FILE" ] && return
|
|
615
|
+
local tmp="\${SYNKRO_CONSENT_FILE}.tmp"
|
|
616
|
+
grep -v "^$sid\\\\t$hash\\\\tconsumed$" "$SYNKRO_CONSENT_FILE" > "$tmp" 2>/dev/null && mv "$tmp" "$SYNKRO_CONSENT_FILE" 2>/dev/null || true
|
|
617
|
+
}
|
|
618
|
+
|
|
589
619
|
synkro_post_with_retry() {
|
|
590
620
|
local url="$1" body="$2" timeout="\${3:-8}"
|
|
591
621
|
local resp
|
|
@@ -667,11 +697,21 @@ if [ "$ROUTE" = "local" ]; then
|
|
|
667
697
|
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
668
698
|
synkro_capture_local "bash" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
|
|
669
699
|
else
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
'{
|
|
674
|
-
|
|
700
|
+
CMD_HASH=$(printf '%s' "$COMMAND" | shasum -a 256 | cut -c1-16)
|
|
701
|
+
if [ -n "$SESSION_ID" ] && synkro_consent_has_active "$SESSION_ID" "$CMD_HASH"; then
|
|
702
|
+
REASON="[synkro:local] bashGuard \u2192 pass (consented retry): \${LOCAL_REASON:-retrying previously consented command}"
|
|
703
|
+
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
704
|
+
synkro_capture_local "bash" "pass" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
|
|
705
|
+
else
|
|
706
|
+
if [ -n "$SESSION_ID" ] && synkro_consent_has_consumed "$SESSION_ID" "$CMD_HASH"; then
|
|
707
|
+
synkro_consent_clear_consumed "$SESSION_ID" "$CMD_HASH"
|
|
708
|
+
fi
|
|
709
|
+
if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
|
|
710
|
+
REASON="[synkro:local] bashGuard \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
|
|
711
|
+
jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
|
|
712
|
+
'{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
|
|
713
|
+
synkro_capture_local "bash" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
|
|
714
|
+
fi
|
|
675
715
|
fi
|
|
676
716
|
else
|
|
677
717
|
jq -n --arg m "[synkro:local] bashGuard \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
|
|
@@ -1189,6 +1229,19 @@ BODY=$(jq -n --arg sid "$SESSION_ID" --arg tid "$TOOL_USE_ID" \\
|
|
|
1189
1229
|
--argjson err "$IS_ERROR" --arg ch "$CMD_HASH" \\
|
|
1190
1230
|
'{capture_type:"bash_followup",session_id:$sid,tool_use_id:$tid,is_error:$err,command_hash:$ch}')
|
|
1191
1231
|
|
|
1232
|
+
# Local consent tracking: command ran = user consented
|
|
1233
|
+
# On success \u2192 consume (next attempt blocks fresh)
|
|
1234
|
+
# On failure \u2192 grant active (retry allowed)
|
|
1235
|
+
if [ -n "$CMD_HASH" ] && [ -n "$SESSION_ID" ]; then
|
|
1236
|
+
if [ "$IS_ERROR" = "false" ]; then
|
|
1237
|
+
synkro_consent_consume "$SESSION_ID" "$CMD_HASH"
|
|
1238
|
+
else
|
|
1239
|
+
if ! synkro_consent_has_active "$SESSION_ID" "$CMD_HASH"; then
|
|
1240
|
+
synkro_consent_grant "$SESSION_ID" "$CMD_HASH"
|
|
1241
|
+
fi
|
|
1242
|
+
fi
|
|
1243
|
+
fi
|
|
1244
|
+
|
|
1192
1245
|
curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
|
|
1193
1246
|
-H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
|
|
1194
1247
|
-d "$BODY" --max-time 2 >/dev/null 2>&1 || true
|
|
@@ -1446,6 +1499,16 @@ if [ -n "$CMD" ]; then
|
|
|
1446
1499
|
CMD_HASH=$(printf '%s' "$CMD" | shasum -a 256 | cut -c1-16)
|
|
1447
1500
|
fi
|
|
1448
1501
|
|
|
1502
|
+
if [ -n "$CMD_HASH" ] && [ -n "$SESSION_ID" ]; then
|
|
1503
|
+
if [ "$IS_ERROR" = "false" ]; then
|
|
1504
|
+
synkro_consent_consume "$SESSION_ID" "$CMD_HASH"
|
|
1505
|
+
else
|
|
1506
|
+
if ! synkro_consent_has_active "$SESSION_ID" "$CMD_HASH"; then
|
|
1507
|
+
synkro_consent_grant "$SESSION_ID" "$CMD_HASH"
|
|
1508
|
+
fi
|
|
1509
|
+
fi
|
|
1510
|
+
fi
|
|
1511
|
+
|
|
1449
1512
|
if [ -n "$SESSION_ID" ] && [ -n "$TOOL_USE_ID" ]; then
|
|
1450
1513
|
(
|
|
1451
1514
|
BODY=$(jq -n --arg sid "$SESSION_ID" --arg tid "$TOOL_USE_ID" \\
|
|
@@ -3606,7 +3669,7 @@ function writeConfigEnv(opts) {
|
|
|
3606
3669
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3607
3670
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3608
3671
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3609
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
3672
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.24")}`
|
|
3610
3673
|
];
|
|
3611
3674
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
3612
3675
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|