@synkro-sh/cli 1.3.40 → 1.3.41

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
@@ -3746,7 +3746,7 @@ function writeConfigEnv(opts) {
3746
3746
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
3747
3747
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
3748
3748
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
3749
- `SYNKRO_VERSION=${shellQuoteSingle("1.3.40")}`
3749
+ `SYNKRO_VERSION=${shellQuoteSingle("1.3.41")}`
3750
3750
  ];
3751
3751
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
3752
3752
  if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
@@ -4793,54 +4793,9 @@ async function ensureOpenPr(repo, prNumber, sha) {
4793
4793
  try {
4794
4794
  pr = ghJson(["api", `/repos/${repo}/pulls/${prNumber}`]);
4795
4795
  } catch {
4796
- return { prNumber, sha, branched: false };
4797
- }
4798
- if (pr.state === "open") {
4799
- return { prNumber, sha, branched: false };
4800
- }
4801
- if (pr.merged) {
4802
- console.log(`PR #${prNumber} is merged. Scanning original diff and posting findings there.
4803
- `);
4804
- return { prNumber, sha: pr.head.sha, branched: false };
4805
- }
4806
- console.log(`PR #${prNumber} is closed. Creating a scan branch...
4807
- `);
4808
- const scanBranch = `synkro/scan-${pr.head.ref}-${Date.now()}`;
4809
- try {
4810
- execSync5(`gh api -X POST /repos/${repo}/git/refs --input -`, {
4811
- encoding: "utf-8",
4812
- input: JSON.stringify({ ref: `refs/heads/${scanBranch}`, sha: pr.head.sha }),
4813
- stdio: ["pipe", "pipe", "pipe"]
4814
- });
4815
- } catch (err) {
4816
- console.warn(`Failed to create scan branch: ${err.message}`);
4817
- return { prNumber, sha, branched: false };
4818
- }
4819
- try {
4820
- const newPrBody = `Security scan of closed PR #${prNumber} (\`${pr.head.ref}\`).
4821
-
4822
- This PR contains no code changes \u2014 it exists so Synkro can post review findings on an active PR.`;
4823
- const result = ghJson([
4824
- "api",
4825
- "-X",
4826
- "POST",
4827
- `/repos/${repo}/pulls`,
4828
- "-f",
4829
- `title=Synkro Scan: ${pr.title}`,
4830
- "-f",
4831
- `body=${newPrBody}`,
4832
- "-f",
4833
- `head=${scanBranch}`,
4834
- "-f",
4835
- `base=${pr.base.ref}`
4836
- ]);
4837
- console.log(`Opened PR #${result.number} for scan findings.
4838
- `);
4839
- return { prNumber: result.number, sha: result.head.sha, branched: true };
4840
- } catch (err) {
4841
- console.warn(`Failed to open scan PR: ${err.message}`);
4842
- return { prNumber, sha, branched: false };
4796
+ return { prNumber, sha, branched: false, prState: "unknown", merged: false };
4843
4797
  }
4798
+ return { prNumber, sha: pr.head.sha, branched: false, prState: pr.state, merged: pr.merged };
4844
4799
  }
4845
4800
  function getPrFiles(repo, prNumber) {
4846
4801
  const data = ghJson([
@@ -5117,7 +5072,28 @@ ${linesStr}: ${first.description}
5117
5072
  severity: maxSeverity
5118
5073
  };
5119
5074
  }
5120
- function postPrReview(repo, prNumber, sha, review) {
5075
+ function postPrReview(repo, prNumber, sha, review, skipLineReview = false) {
5076
+ function postIssueComment() {
5077
+ try {
5078
+ const body = `## \u{1F512} Synkro Security Review
5079
+
5080
+ ${review.summary}
5081
+
5082
+ ` + review.comments.map((c) => `**${c.path}:${c.line}** \u2014 ${c.body}`).join("\n\n");
5083
+ execSync5(`gh api -X POST /repos/${repo}/issues/${prNumber}/comments --input -`, {
5084
+ encoding: "utf-8",
5085
+ input: JSON.stringify({ body }),
5086
+ stdio: ["pipe", "ignore", "pipe"]
5087
+ });
5088
+ console.log(" \u2713 Posted issue comment with findings.");
5089
+ } catch (err) {
5090
+ console.warn("Failed to post issue comment:", err.message);
5091
+ }
5092
+ }
5093
+ if (skipLineReview) {
5094
+ postIssueComment();
5095
+ return;
5096
+ }
5121
5097
  const preferredEvent = review.severity === "critical" || review.severity === "high" ? "REQUEST_CHANGES" : "COMMENT";
5122
5098
  function tryPost(event) {
5123
5099
  const body = JSON.stringify({
@@ -5143,27 +5119,12 @@ ${review.summary}`,
5143
5119
  if (combined.includes("own pull request") && event === "REQUEST_CHANGES") {
5144
5120
  return false;
5145
5121
  }
5146
- console.warn(`Failed to post review: ${(stderr || stdout || err.message).slice(0, 200)}`);
5147
5122
  return false;
5148
5123
  }
5149
5124
  }
5150
5125
  if (tryPost(preferredEvent)) return;
5151
5126
  if (preferredEvent === "REQUEST_CHANGES" && tryPost("COMMENT")) return;
5152
- try {
5153
- const fallbackBody = `## \u{1F512} Synkro Security Review
5154
-
5155
- ${review.summary}
5156
-
5157
- ` + review.comments.map((c) => `**${c.path}:${c.line}** \u2014 ${c.body}`).join("\n\n");
5158
- execSync5(`gh api -X POST /repos/${repo}/issues/${prNumber}/comments --input -`, {
5159
- encoding: "utf-8",
5160
- input: JSON.stringify({ body: fallbackBody }),
5161
- stdio: ["pipe", "ignore", "pipe"]
5162
- });
5163
- console.log(" \u2713 Posted fallback issue comment.");
5164
- } catch (err2) {
5165
- console.warn("Failed to post fallback comment:", err2.message);
5166
- }
5127
+ postIssueComment();
5167
5128
  }
5168
5129
  function postCheckRun(repo, sha, conclusion, findings) {
5169
5130
  const summary = findings.length === 0 ? "No security findings." : `${findings.length} finding(s):
@@ -5318,7 +5279,8 @@ Total: ${allFindings.length} finding(s) across ${eligible.length} file(s) in ${t
5318
5279
  const review = await spawnOpusConsolidator(allFindings, claudeToken);
5319
5280
  console.log(` \u2192 ${review.comments.length} review comment(s), severity: ${review.severity}`);
5320
5281
  if (review.comments.length > 0) {
5321
- postPrReview(repo, activePrNumber, activeSha, review);
5282
+ const skipLineReview = prTarget.prState === "closed" && !prTarget.merged;
5283
+ postPrReview(repo, activePrNumber, activeSha, review, skipLineReview);
5322
5284
  }
5323
5285
  }
5324
5286
  const conclusion = shouldFail(allFindings, failThreshold) ? "failure" : "success";