@cencori/scan 0.4.5 → 0.4.6

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/cli.js CHANGED
@@ -856,17 +856,29 @@ async function generateFixes(issues, fileContents) {
856
856
  "Authorization": `Bearer ${apiKey}`
857
857
  },
858
858
  body: JSON.stringify({
859
- model: "meta-llama/llama-4-scout-17b-16e-instruct",
859
+ model: "gpt-4o-mini",
860
+ // Use reliable model
860
861
  messages: [
861
862
  {
862
863
  role: "system",
863
- content: `You are a security engineer. Generate secure code fixes. For secrets, use environment variables. For XSS, use sanitization. Respond in JSON: {"fixedCode": "the fixed code snippet", "explanation": "what was changed"}`
864
+ content: `You are a security engineer fixing code vulnerabilities. Generate secure code fixes.
865
+
866
+ IMPORTANT: Respond ONLY with valid JSON in this exact format:
867
+ {"fixedCode": "the complete fixed code snippet", "explanation": "brief explanation of what was changed"}
868
+
869
+ Rules:
870
+ - For hardcoded secrets: Replace with environment variables (process.env.VAR_NAME)
871
+ - For XSS vulnerabilities: Add proper escaping/sanitization
872
+ - For SQL injection: Use parameterized queries
873
+ - For exposed routes: Add authentication middleware
874
+ - Keep the same code structure, only fix the security issue`
864
875
  },
865
876
  {
866
877
  role: "user",
867
878
  content: `Fix this security issue:
868
879
  Type: ${issue.type}
869
880
  Name: ${issue.name}
881
+ Severity: ${issue.severity}
870
882
  File: ${issue.file}:${issue.line}
871
883
 
872
884
  Code to fix:
@@ -874,32 +886,81 @@ Code to fix:
874
886
  ${codeSnippet}
875
887
  \`\`\`
876
888
 
877
- Generate a secure fix.`
889
+ Respond with JSON only.`
878
890
  }
879
891
  ],
880
892
  temperature: 0,
881
- max_tokens: 500
893
+ max_tokens: 1e3
882
894
  })
883
895
  });
884
896
  if (!response.ok) {
885
- throw new Error(`API error: ${response.status}`);
897
+ const errorText = await response.text();
898
+ console.error(`[AI] API error for ${issue.file}:${issue.line}: ${response.status} - ${errorText}`);
899
+ results.push({
900
+ issue,
901
+ originalCode: codeSnippet,
902
+ fixedCode: codeSnippet,
903
+ // Same as original = no fix
904
+ explanation: `API error: ${response.status}`,
905
+ applied: false
906
+ });
907
+ continue;
886
908
  }
887
909
  const data = await response.json();
888
- const content_response = data.choices[0]?.message?.content || "{}";
889
- const parsed = JSON.parse(content_response);
890
- results.push({
891
- issue,
892
- originalCode: codeSnippet,
893
- fixedCode: parsed.fixedCode || codeSnippet,
894
- explanation: parsed.explanation || "No explanation provided",
895
- applied: false
896
- });
897
- } catch {
910
+ if (data.error) {
911
+ console.error(`[AI] API returned error: ${data.error.message}`);
912
+ results.push({
913
+ issue,
914
+ originalCode: codeSnippet,
915
+ fixedCode: codeSnippet,
916
+ explanation: `AI error: ${data.error.message}`,
917
+ applied: false
918
+ });
919
+ continue;
920
+ }
921
+ const content_response = data.choices[0]?.message?.content || "";
922
+ let jsonStr = content_response;
923
+ const jsonMatch = content_response.match(/```(?:json)?\s*([\s\S]*?)```/);
924
+ if (jsonMatch) {
925
+ jsonStr = jsonMatch[1].trim();
926
+ }
927
+ try {
928
+ const parsed = JSON.parse(jsonStr);
929
+ const fixedCode = parsed.fixedCode || parsed.fixed_code || "";
930
+ if (fixedCode && fixedCode !== codeSnippet) {
931
+ results.push({
932
+ issue,
933
+ originalCode: codeSnippet,
934
+ fixedCode,
935
+ explanation: parsed.explanation || "Security fix applied",
936
+ applied: false
937
+ });
938
+ } else {
939
+ results.push({
940
+ issue,
941
+ originalCode: codeSnippet,
942
+ fixedCode: codeSnippet,
943
+ explanation: "AI could not generate a fix for this issue",
944
+ applied: false
945
+ });
946
+ }
947
+ } catch (parseError) {
948
+ console.error(`[AI] JSON parse error for ${issue.file}:${issue.line}:`, parseError);
949
+ results.push({
950
+ issue,
951
+ originalCode: codeSnippet,
952
+ fixedCode: codeSnippet,
953
+ explanation: "Failed to parse AI response",
954
+ applied: false
955
+ });
956
+ }
957
+ } catch (error) {
958
+ console.error(`[AI] Request failed for ${issue.file}:${issue.line}:`, error);
898
959
  results.push({
899
960
  issue,
900
961
  originalCode: codeSnippet,
901
962
  fixedCode: codeSnippet,
902
- explanation: "Unable to generate fix - manual review required",
963
+ explanation: `Request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
903
964
  applied: false
904
965
  });
905
966
  }
@@ -1158,7 +1219,7 @@ No commits found in the specified period.
1158
1219
  // src/cli.ts
1159
1220
  var fs3 = __toESM(require("fs"));
1160
1221
  var path3 = __toESM(require("path"));
1161
- var VERSION = "0.4.5";
1222
+ var VERSION = "0.4.6";
1162
1223
  var scoreStyles = {
1163
1224
  A: { color: import_chalk.default.green },
1164
1225
  B: { color: import_chalk.default.blue },
@@ -1394,12 +1455,41 @@ async function handleAutoFix(result, targetPath) {
1394
1455
  );
1395
1456
  fixSpinner.succeed(`Generated ${fixes.length} fixes`);
1396
1457
  console.log();
1458
+ const actualFixes = fixes.filter((f) => f.fixedCode !== f.originalCode);
1459
+ const failedFixes = fixes.filter((f) => f.fixedCode === f.originalCode);
1460
+ if (failedFixes.length > 0) {
1461
+ console.log(import_chalk.default.gray(` Note: ${failedFixes.length} issues could not be auto-fixed (saved for manual review)`));
1462
+ console.log();
1463
+ }
1464
+ if (actualFixes.length === 0) {
1465
+ console.log(import_chalk.default.yellow(" No fixes could be generated by AI."));
1466
+ console.log(import_chalk.default.gray(" This may be due to API issues or complex code patterns."));
1467
+ const fixesFile = ".cencori-fixes.json";
1468
+ const fixesData = {
1469
+ generated_at: (/* @__PURE__ */ new Date()).toISOString(),
1470
+ total_fixes: failedFixes.length,
1471
+ note: "AI could not generate automatic fixes for these issues",
1472
+ fixes: failedFixes.map((f) => ({
1473
+ file: f.issue.file,
1474
+ line: f.issue.line,
1475
+ issue_type: f.issue.type,
1476
+ issue_name: f.issue.name,
1477
+ severity: f.issue.severity,
1478
+ original_code: f.originalCode,
1479
+ explanation: f.explanation
1480
+ }))
1481
+ };
1482
+ fs3.writeFileSync(fixesFile, JSON.stringify(fixesData, null, 2));
1483
+ console.log(import_chalk.default.cyan(` Issues saved to ${import_chalk.default.bold(fixesFile)} for manual review.`));
1484
+ console.log();
1485
+ return;
1486
+ }
1397
1487
  const acceptedFixes = [];
1398
1488
  const skippedFixes = [];
1399
1489
  let applyAll = false;
1400
1490
  let skipRest = false;
1401
- for (let i = 0; i < fixes.length; i++) {
1402
- const fix = fixes[i];
1491
+ for (let i = 0; i < actualFixes.length; i++) {
1492
+ const fix = actualFixes[i];
1403
1493
  if (skipRest) {
1404
1494
  skippedFixes.push(fix);
1405
1495
  continue;
@@ -1446,23 +1536,23 @@ async function handleAutoFix(result, targetPath) {
1446
1536
  } else if (action === "a") {
1447
1537
  applyAll = true;
1448
1538
  acceptedFixes.push(fix);
1449
- for (let j = i + 1; j < fixes.length; j++) {
1450
- acceptedFixes.push(fixes[j]);
1539
+ for (let j = i + 1; j < actualFixes.length; j++) {
1540
+ acceptedFixes.push(actualFixes[j]);
1451
1541
  }
1452
- console.log(import_chalk.default.green(` \u2714 Applying all ${fixes.length - i} remaining fixes`));
1542
+ console.log(import_chalk.default.green(` \u2714 Applying all ${actualFixes.length - i} remaining fixes`));
1453
1543
  break;
1454
1544
  } else if (action === "s") {
1455
1545
  skipRest = true;
1456
1546
  skippedFixes.push(fix);
1457
- for (let j = i + 1; j < fixes.length; j++) {
1458
- skippedFixes.push(fixes[j]);
1547
+ for (let j = i + 1; j < actualFixes.length; j++) {
1548
+ skippedFixes.push(actualFixes[j]);
1459
1549
  }
1460
- console.log(import_chalk.default.yellow(` \u2298 Skipping ${fixes.length - i} remaining fixes`));
1550
+ console.log(import_chalk.default.yellow(` \u2298 Skipping ${actualFixes.length - i} remaining fixes`));
1461
1551
  break;
1462
1552
  } else if (action === "q") {
1463
1553
  skippedFixes.push(fix);
1464
- for (let j = i + 1; j < fixes.length; j++) {
1465
- skippedFixes.push(fixes[j]);
1554
+ for (let j = i + 1; j < actualFixes.length; j++) {
1555
+ skippedFixes.push(actualFixes[j]);
1466
1556
  }
1467
1557
  console.log(import_chalk.default.gray(" Stopped reviewing"));
1468
1558
  break;