@synkro-sh/cli 1.1.0 → 1.1.2

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
@@ -800,10 +800,23 @@ if [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; t
800
800
  # and gets the verdict text back. Steady-state ~1.5\u20133s per grading vs
801
801
  # ~14s for cold \`claude --print\`. Falls back to direct \`claude --print\`
802
802
  # if the daemon binary or primer is missing.
803
+
804
+ # Fetch the caller's visible org rules so the grader can evaluate against
805
+ # custom policies, not just the primer's hardcoded baseline. Without this,
806
+ # audit-mode rules silently pass on free tier \u2014 the rule exists in the DB
807
+ # but never reaches the model. Bounded at 1.5s; on failure proceed with
808
+ # an empty rules array (degrades to baseline-only judging).
809
+ ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
810
+ -H "Authorization: Bearer $JWT" \\
811
+ --max-time 1.5 2>/dev/null \\
812
+ | jq -c '[.rules[]? | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
813
+ if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
814
+
803
815
  GRADER_PROMPT_FILE=$(mktemp -t synkro-grade.XXXXXX)
804
816
  trap "rm -f \\"$GRADER_PROMPT_FILE\\"" EXIT
805
817
  printf 'File: %s\\n' "$FILE_PATH" > "$GRADER_PROMPT_FILE"
806
- printf 'User intent: %s\\n\\n' "\${USER_INTENT:-none stated}" >> "$GRADER_PROMPT_FILE"
818
+ printf 'User intent: %s\\n' "\${USER_INTENT:-none stated}" >> "$GRADER_PROMPT_FILE"
819
+ printf 'Org rules: %s\\n\\n' "$ORG_RULES" >> "$GRADER_PROMPT_FILE"
807
820
  printf 'Diff:\\n' >> "$GRADER_PROMPT_FILE"
808
821
  printf '%s\\n' "$PROPOSED" >> "$GRADER_PROMPT_FILE"
809
822
 
@@ -1613,6 +1626,17 @@ if __name__ == "__main__":
1613
1626
  `;
1614
1627
  GRADER_PRIMER_EDIT = `You are Synkro's security pre-check grader. You will be given proposed file diffs from an AI coding agent. For each one, decide whether it has security issues \u2014 possibly multiple distinct ones in the same diff.
1615
1628
 
1629
+ EACH GRADING REQUEST INCLUDES:
1630
+ - File: the path being written
1631
+ - User intent: what the user told the agent to do
1632
+ - Org rules: a JSON array of this organization's active policies, each with rule_id, text, severity, category. THESE ARE THE PRIMARY SOURCE OF TRUTH. If a rule's text describes behavior that matches the diff, flag it. Use that rule's rule_id verbatim, not a synthesized one.
1633
+ - Diff: the proposed file content
1634
+
1635
+ PRIORITY ORDER:
1636
+ 1. ORG RULES first. If the diff matches the prose of any org rule, that's a violation \u2014 emit the rule's rule_id, the rule's severity, and a one-line reason citing file:line + the matching behavior + a concrete fix. Don't second-guess the org's rules \u2014 if the rule says "Agents must not iterate 1Password vaults" and the diff loops over \`op item list\`, that's a hit.
1637
+ 2. BASELINE security issues (hardcoded real-looking secrets, eval/exec on user input, SQL string concat, MD5/SHA1 for security, unsafe deserialization, command injection, path traversal, env-dump logging). Flag these even if no org rule covers them \u2014 they're universally bad. Use a sensible snake_case rule_id like \`no-hardcoded-secrets\`, \`eval-on-user-input\`.
1638
+ 3. Stylistic issues, placeholder fixtures, test files (path under /tests/, /__tests__/, *.test.*), and config-only files are NOT security issues \u2014 return ok=true.
1639
+
1616
1640
  OUTPUT RULES \u2014 strictest possible, no exceptions:
1617
1641
 
1618
1642
  1. NO reasoning. NO preamble. NO commentary.
@@ -1620,7 +1644,7 @@ OUTPUT RULES \u2014 strictest possible, no exceptions:
1620
1644
  3. JSON shape:
1621
1645
  {"ok": true | false,
1622
1646
  "violations": [
1623
- {"rule_id": "<short snake_case slug, e.g. no-hardcoded-secrets>",
1647
+ {"rule_id": "<rule_id from Org rules if matched, else short snake_case slug>",
1624
1648
  "severity": "low" | "medium" | "high" | "critical",
1625
1649
  "category": "<short snake_case>",
1626
1650
  "reason": "<= 25 words, file:line + issue + fix",
@@ -1633,6 +1657,8 @@ ok=false \u2192 list EVERY distinct violation. A diff that hardcodes a Stripe ke
1633
1657
 
1634
1658
  ONE VIOLATION = ONE ENTRY. If the same line/issue can be described multiple ways ("uses concat", "missing $1 placeholder", "not parameterized"), pick the most specific rule_id and write a single entry. Multiple entries are warranted only when the diff has multiple INDEPENDENTLY-FIXABLE issues.
1635
1659
 
1660
+ ORG RULE PRECEDENCE: when an org rule matches, use ITS rule_id and severity verbatim \u2014 never override "critical" down to "medium" because the diff seems mild, and never invent your own rule_id when an org rule applies. The user authored those rules for a reason.
1661
+
1636
1662
  Reply with exactly: <synkro-verdict>{"ok":true,"violations":[]}</synkro-verdict>
1637
1663
  `;
1638
1664
  GRADER_PRIMER_BASH = `You are Synkro's bash command safety judge for AI coding agents. You will be given a proposed shell command, the user's most recent stated intent, the last 3-5 user-role messages from the chat (oldest first, JSON array under "Recent user messages"), and recent agent actions. Decide whether to allow or warn.
@@ -2045,7 +2071,7 @@ function writeConfigEnv(opts) {
2045
2071
  `SYNKRO_GATEWAY_URL=${shellQuoteSingle(safeGateway)}`,
2046
2072
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
2047
2073
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
2048
- `SYNKRO_VERSION=${shellQuoteSingle("1.1.0")}`
2074
+ `SYNKRO_VERSION=${shellQuoteSingle("1.1.2")}`
2049
2075
  ];
2050
2076
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
2051
2077
  if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
@@ -3180,7 +3206,7 @@ async function updateCommand() {
3180
3206
  console.log("Refreshing Synkro hook configs and prompts...\n");
3181
3207
  await installCommand();
3182
3208
  console.log("\n\u2713 Synkro updated.");
3183
- console.log("To update the CLI binary itself, run: curl -fsSL https://get.synkro.sh | bash");
3209
+ console.log("To upgrade the CLI itself, run: npm install -g @synkro-sh/cli@latest");
3184
3210
  }
3185
3211
  var init_update = __esm({
3186
3212
  "cli/commands/update.ts"() {
@@ -3263,7 +3289,8 @@ function printHelp() {
3263
3289
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
3264
3290
 
3265
3291
  Usage:
3266
- synkro <command> [options]
3292
+ synkro-cli <command> [options] (recommended \u2014 avoids name collisions)
3293
+ synkro <command> [options] (alias)
3267
3294
 
3268
3295
  Commands:
3269
3296
  install [--force] Install Synkro hooks for detected agents (Claude Code, etc.)