@synkro-sh/cli 1.4.23 → 1.4.25
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 -22
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -499,23 +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 (SYNKRO_RULES uses single quotes to avoid expansion issues with JSON)
|
|
516
|
-
{ printf 'SYNKRO_CAPTURE_DEPTH="%s"\\nSYNKRO_TIER="%s"\\n' "$SYNKRO_CAPTURE_DEPTH" "$SYNKRO_TIER"
|
|
517
|
-
printf "SYNKRO_RULES='%s'\\n" "$SYNKRO_RULES"
|
|
518
|
-
} > "$cache" 2>/dev/null || true
|
|
519
510
|
}
|
|
520
511
|
|
|
521
512
|
# Decide routing: "local" (grade on device) or "cloud" (POST to server)
|
|
@@ -551,13 +542,19 @@ synkro_parse_local_verdict() {
|
|
|
551
542
|
LOCAL_REASON=$(printf '%s' "$inner" | sed -nE 's|.*<reason>(.*)</reason>.*|\\1|p' | head -1)
|
|
552
543
|
[ -z "$LOCAL_REASON" ] && LOCAL_REASON=$(printf '%s' "$inner" | sed -nE 's|.*<reasoning>(.*)</reasoning>.*|\\1|p' | head -1)
|
|
553
544
|
if [ "$LOCAL_OK" = "false" ]; then
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
[ -z "$
|
|
558
|
-
|
|
559
|
-
|
|
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
|
|
560
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)
|
|
561
558
|
fi
|
|
562
559
|
}
|
|
563
560
|
|
|
@@ -588,6 +585,37 @@ synkro_rule_mode() {
|
|
|
588
585
|
echo "$m"
|
|
589
586
|
}
|
|
590
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
|
+
|
|
591
619
|
synkro_post_with_retry() {
|
|
592
620
|
local url="$1" body="$2" timeout="\${3:-8}"
|
|
593
621
|
local resp
|
|
@@ -669,11 +697,21 @@ if [ "$ROUTE" = "local" ]; then
|
|
|
669
697
|
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
670
698
|
synkro_capture_local "bash" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
|
|
671
699
|
else
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
'{
|
|
676
|
-
|
|
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
|
+
'{systemMessage:$reason,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
|
|
677
715
|
fi
|
|
678
716
|
else
|
|
679
717
|
jq -n --arg m "[synkro:local] bashGuard \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
|
|
@@ -1191,6 +1229,19 @@ BODY=$(jq -n --arg sid "$SESSION_ID" --arg tid "$TOOL_USE_ID" \\
|
|
|
1191
1229
|
--argjson err "$IS_ERROR" --arg ch "$CMD_HASH" \\
|
|
1192
1230
|
'{capture_type:"bash_followup",session_id:$sid,tool_use_id:$tid,is_error:$err,command_hash:$ch}')
|
|
1193
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
|
+
|
|
1194
1245
|
curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
|
|
1195
1246
|
-H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
|
|
1196
1247
|
-d "$BODY" --max-time 2 >/dev/null 2>&1 || true
|
|
@@ -1448,6 +1499,16 @@ if [ -n "$CMD" ]; then
|
|
|
1448
1499
|
CMD_HASH=$(printf '%s' "$CMD" | shasum -a 256 | cut -c1-16)
|
|
1449
1500
|
fi
|
|
1450
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
|
+
|
|
1451
1512
|
if [ -n "$SESSION_ID" ] && [ -n "$TOOL_USE_ID" ]; then
|
|
1452
1513
|
(
|
|
1453
1514
|
BODY=$(jq -n --arg sid "$SESSION_ID" --arg tid "$TOOL_USE_ID" \\
|
|
@@ -3608,7 +3669,7 @@ function writeConfigEnv(opts) {
|
|
|
3608
3669
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3609
3670
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3610
3671
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3611
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
3672
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.25")}`
|
|
3612
3673
|
];
|
|
3613
3674
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
3614
3675
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|