@clear-capabilities/agentic-security-scanner 0.78.0 → 0.80.0

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.
Files changed (126) hide show
  1. package/bin/.agentic-security/findings.json +16 -16
  2. package/bin/.agentic-security/last-scan.json +16 -16
  3. package/bin/.agentic-security/last-scan.json.sig +1 -1
  4. package/bin/.agentic-security/scan-history.json +51 -0
  5. package/bin/.agentic-security/streak.json +5 -5
  6. package/bin/agentic-security.js +22 -7
  7. package/dist/178.index.js +1 -1
  8. package/dist/333.index.js +283 -0
  9. package/dist/384.index.js +1 -1
  10. package/dist/476.index.js +5 -5
  11. package/dist/637.index.js +1 -1
  12. package/dist/700.index.js +138 -0
  13. package/dist/718.index.js +53 -0
  14. package/dist/838.index.js +1 -1
  15. package/dist/985.index.js +95 -1
  16. package/dist/agentic-security.mjs +83 -83
  17. package/dist/agentic-security.mjs.sha256 +1 -1
  18. package/package.json +6 -4
  19. package/src/.agentic-security/findings.json +29799 -7803
  20. package/src/.agentic-security/last-scan.json +29799 -7803
  21. package/src/.agentic-security/last-scan.json.sig +1 -1
  22. package/src/.agentic-security/scan-history.json +5119 -2611
  23. package/src/.agentic-security/streak.json +6 -6
  24. package/src/dataflow/.agentic-security/findings.json +2879 -308
  25. package/src/dataflow/.agentic-security/last-scan.json +2879 -308
  26. package/src/dataflow/.agentic-security/last-scan.json.sig +1 -1
  27. package/src/dataflow/.agentic-security/scan-history.json +68 -520
  28. package/src/dataflow/.agentic-security/streak.json +6 -7
  29. package/src/dataflow/cross-service-taint.js +201 -0
  30. package/src/dataflow/engine.js +52 -8
  31. package/src/dataflow/formal-verify.js +204 -0
  32. package/src/dataflow/ifds-precise.js +222 -0
  33. package/src/dataflow/k2-summary-cache.js +153 -0
  34. package/src/dataflow/lib-taint-summaries.js +198 -0
  35. package/src/dataflow/privacy-taint.js +205 -0
  36. package/src/dataflow/smt-feasibility.js +189 -0
  37. package/src/engine.js +890 -132
  38. package/src/integrations/index.js +2 -1
  39. package/src/ir/.agentic-security/findings.json +240 -6
  40. package/src/ir/.agentic-security/last-scan.json +240 -6
  41. package/src/ir/.agentic-security/last-scan.json.sig +1 -1
  42. package/src/ir/.agentic-security/scan-history.json +16 -594
  43. package/src/ir/.agentic-security/streak.json +8 -9
  44. package/src/ir/callgraph.js +27 -7
  45. package/src/ir/cpp-preprocessor.js +142 -0
  46. package/src/ir/csharp-ir.js +604 -0
  47. package/src/ir/universal-ir.js +403 -0
  48. package/src/llm-validator/index.js +7 -5
  49. package/src/mcp/.agentic-security/findings.json +8632 -0
  50. package/src/mcp/.agentic-security/last-scan.json +8632 -0
  51. package/src/mcp/.agentic-security/last-scan.json.sig +1 -0
  52. package/src/mcp/.agentic-security/scan-history.json +143 -0
  53. package/src/mcp/.agentic-security/streak.json +20 -0
  54. package/src/mcp/audit.js +5 -0
  55. package/src/mcp/tools.js +90 -1
  56. package/src/posture/.agentic-security/findings.json +16809 -4367
  57. package/src/posture/.agentic-security/last-scan.json +16809 -4367
  58. package/src/posture/.agentic-security/last-scan.json.sig +1 -1
  59. package/src/posture/.agentic-security/scan-history.json +6689 -177
  60. package/src/posture/.agentic-security/streak.json +8 -7
  61. package/src/posture/api-contract.js +193 -0
  62. package/src/posture/attack-taxonomy.js +227 -0
  63. package/src/posture/calibration-drift.js +2 -1
  64. package/src/posture/calibration.js +3 -2
  65. package/src/posture/compliance-policy.js +218 -0
  66. package/src/posture/composite-risk.js +122 -0
  67. package/src/posture/csharp-analysis.js +330 -0
  68. package/src/posture/exploit-bundle.js +210 -0
  69. package/src/posture/federated-learning.js +172 -0
  70. package/src/posture/fix-history.js +8 -2
  71. package/src/posture/license-attributions.js +94 -0
  72. package/src/posture/license-graph.js +238 -0
  73. package/src/posture/pqc-migration-plan.js +158 -0
  74. package/src/posture/profile.js +4 -5
  75. package/src/posture/reachability-filter.js +33 -2
  76. package/src/posture/realtime-cve-monitor.js +214 -0
  77. package/src/posture/rule-overrides.js +2 -3
  78. package/src/posture/rule-pack-signing.js +2 -3
  79. package/src/posture/rule-synthesis.js +5 -6
  80. package/src/posture/runtime-correlation.js +174 -0
  81. package/src/posture/sbom-diff.js +171 -0
  82. package/src/posture/sca-policy.js +235 -0
  83. package/src/posture/sca-upgrade.js +259 -0
  84. package/src/posture/security-trend.js +4 -7
  85. package/src/posture/state-dir.js +124 -0
  86. package/src/posture/streak.js +3 -0
  87. package/src/posture/suppressions.js +5 -8
  88. package/src/posture/threat-model-auto.js +268 -0
  89. package/src/posture/triage-learning.js +170 -0
  90. package/src/posture/triage.js +29 -6
  91. package/src/posture/validator-metrics.js +3 -6
  92. package/src/sast/.agentic-security/findings.json +996 -32
  93. package/src/sast/.agentic-security/last-scan.json +996 -32
  94. package/src/sast/.agentic-security/last-scan.json.sig +1 -1
  95. package/src/sast/.agentic-security/scan-history.json +565 -32
  96. package/src/sast/.agentic-security/streak.json +10 -8
  97. package/src/sast/_secret-entropy.js +145 -0
  98. package/src/sast/cloud-iam.js +312 -0
  99. package/src/sast/cpp.js +138 -4
  100. package/src/sast/crypto-protocol.js +388 -0
  101. package/src/sast/csharp-tokenizer.js +392 -0
  102. package/src/sast/csharp.js +924 -138
  103. package/src/sast/dapp-frontend.js +200 -0
  104. package/src/sast/db-taint.js +24 -0
  105. package/src/sast/k8s-admission.js +271 -0
  106. package/src/sast/llm-app.js +272 -0
  107. package/src/sast/ml-supply-chain.js +259 -0
  108. package/src/sast/mobile.js +224 -0
  109. package/src/sast/post-quantum-crypto.js +348 -0
  110. package/src/sast/rust.js +26 -0
  111. package/src/sast/web3-advanced.js +375 -0
  112. package/src/sca/.agentic-security/findings.json +6044 -171
  113. package/src/sca/.agentic-security/last-scan.json +6044 -171
  114. package/src/sca/.agentic-security/last-scan.json.sig +1 -1
  115. package/src/sca/.agentic-security/scan-history.json +83 -6
  116. package/src/sca/.agentic-security/streak.json +9 -9
  117. package/src/sca/CLAUDE.md +161 -0
  118. package/src/sca/binary-metadata.js +146 -0
  119. package/src/sca/py-package-functions.js +118 -0
  120. package/src/sca/sigstore-verify.js +215 -0
  121. package/src/sca/vendor-detect.js +53 -0
  122. package/src/report/.agentic-security/findings.json +0 -80
  123. package/src/report/.agentic-security/last-scan.json +0 -80
  124. package/src/report/.agentic-security/last-scan.json.sig +0 -1
  125. package/src/report/.agentic-security/scan-history.json +0 -35
  126. package/src/report/.agentic-security/streak.json +0 -22
@@ -0,0 +1 @@
1
+ 45066aa2e5bc1eff0060249590f9b659f87ee1b5bf259c508d585c75d5be346a
@@ -0,0 +1,143 @@
1
+ [
2
+ {
3
+ "timestamp": "2026-05-28T17:48:43.152Z",
4
+ "label": "scan",
5
+ "total": 35,
6
+ "critical": 0,
7
+ "high": 0,
8
+ "medium": 35,
9
+ "low": 0,
10
+ "kev": 0,
11
+ "ids": [
12
+ "struct:audit.js:102:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
13
+ "struct:audit.js:113:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
14
+ "struct:audit.js:127:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
15
+ "struct:audit.js:128:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
16
+ "struct:audit.js:52:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
17
+ "struct:audit.js:54:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
18
+ "struct:audit.js:88:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
19
+ "struct:server.js:32:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
20
+ "struct:server.js:49:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
21
+ "struct:tools.js:159:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
22
+ "struct:tools.js:163:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
23
+ "struct:tools.js:167:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
24
+ "struct:tools.js:196:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
25
+ "struct:tools.js:211:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
26
+ "struct:tools.js:226:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
27
+ "struct:tools.js:227:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
28
+ "struct:tools.js:279:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
29
+ "struct:tools.js:318:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
30
+ "struct:tools.js:326:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
31
+ "struct:tools.js:533:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
32
+ "struct:tools.js:669:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
33
+ "struct:tools.js:744:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
34
+ "struct:tools.js:746:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
35
+ "struct:tools.js:751:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
36
+ "struct:tools.js:754:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
37
+ "struct:tools.js:833:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
38
+ "struct:tools.js:842:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
39
+ "struct:tools.js:871:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
40
+ "struct:tools.js:873:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
41
+ "toctou-fs:audit.js:127",
42
+ "toctou-fs:audit.js:52",
43
+ "toctou-fs:tools.js:196",
44
+ "toctou-fs:tools.js:318",
45
+ "toctou-fs:tools.js:751",
46
+ "toctou-fs:tools.js:833"
47
+ ]
48
+ },
49
+ {
50
+ "timestamp": "2026-05-28T18:12:31.102Z",
51
+ "label": "scan",
52
+ "total": 35,
53
+ "critical": 0,
54
+ "high": 0,
55
+ "medium": 35,
56
+ "low": 0,
57
+ "kev": 0,
58
+ "ids": [
59
+ "struct:audit.js:102:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
60
+ "struct:audit.js:113:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
61
+ "struct:audit.js:127:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
62
+ "struct:audit.js:128:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
63
+ "struct:audit.js:52:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
64
+ "struct:audit.js:54:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
65
+ "struct:audit.js:88:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
66
+ "struct:server.js:32:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
67
+ "struct:server.js:49:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
68
+ "struct:tools.js:159:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
69
+ "struct:tools.js:163:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
70
+ "struct:tools.js:167:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
71
+ "struct:tools.js:196:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
72
+ "struct:tools.js:211:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
73
+ "struct:tools.js:226:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
74
+ "struct:tools.js:227:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
75
+ "struct:tools.js:279:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
76
+ "struct:tools.js:318:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
77
+ "struct:tools.js:326:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
78
+ "struct:tools.js:533:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
79
+ "struct:tools.js:669:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
80
+ "struct:tools.js:744:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
81
+ "struct:tools.js:746:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
82
+ "struct:tools.js:751:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
83
+ "struct:tools.js:754:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
84
+ "struct:tools.js:833:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
85
+ "struct:tools.js:842:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
86
+ "struct:tools.js:871:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
87
+ "struct:tools.js:873:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
88
+ "toctou-fs:audit.js:127",
89
+ "toctou-fs:audit.js:52",
90
+ "toctou-fs:tools.js:196",
91
+ "toctou-fs:tools.js:318",
92
+ "toctou-fs:tools.js:751",
93
+ "toctou-fs:tools.js:833"
94
+ ]
95
+ },
96
+ {
97
+ "timestamp": "2026-05-28T18:14:00.048Z",
98
+ "label": "scan",
99
+ "total": 35,
100
+ "critical": 0,
101
+ "high": 0,
102
+ "medium": 35,
103
+ "low": 0,
104
+ "kev": 0,
105
+ "ids": [
106
+ "struct:audit.js:102:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
107
+ "struct:audit.js:113:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
108
+ "struct:audit.js:127:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
109
+ "struct:audit.js:128:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
110
+ "struct:audit.js:52:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
111
+ "struct:audit.js:54:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
112
+ "struct:audit.js:88:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
113
+ "struct:server.js:32:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
114
+ "struct:server.js:49:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
115
+ "struct:tools.js:159:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
116
+ "struct:tools.js:163:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
117
+ "struct:tools.js:167:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
118
+ "struct:tools.js:196:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
119
+ "struct:tools.js:211:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
120
+ "struct:tools.js:226:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
121
+ "struct:tools.js:227:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
122
+ "struct:tools.js:281:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
123
+ "struct:tools.js:320:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
124
+ "struct:tools.js:328:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
125
+ "struct:tools.js:535:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
126
+ "struct:tools.js:671:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
127
+ "struct:tools.js:746:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
128
+ "struct:tools.js:748:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
129
+ "struct:tools.js:753:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
130
+ "struct:tools.js:756:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
131
+ "struct:tools.js:835:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
132
+ "struct:tools.js:844:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
133
+ "struct:tools.js:873:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
134
+ "struct:tools.js:875:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
135
+ "toctou-fs:audit.js:127",
136
+ "toctou-fs:audit.js:52",
137
+ "toctou-fs:tools.js:196",
138
+ "toctou-fs:tools.js:320",
139
+ "toctou-fs:tools.js:753",
140
+ "toctou-fs:tools.js:835"
141
+ ]
142
+ }
143
+ ]
@@ -0,0 +1,20 @@
1
+ {
2
+ "firstScanDate": "2026-05-28T17:48:43.176Z",
3
+ "lastScanDate": "2026-05-28T18:14:00.070Z",
4
+ "totalScans": 3,
5
+ "daysCleanCritical": 1,
6
+ "lastCleanDate": "2026-05-28",
7
+ "lastCriticalDate": null,
8
+ "hasEverHadCritical": false,
9
+ "bestDaysCleanCritical": 1,
10
+ "totalFindingsAtFirstScan": 40,
11
+ "totalFindingsAtLastScan": 40,
12
+ "totalFixesInferred": 0,
13
+ "lastGrade": "A-",
14
+ "bestGrade": "A-",
15
+ "launchCheckPassedAt": null,
16
+ "achievements": [
17
+ "first-scan"
18
+ ],
19
+ "previousGrade": "A-"
20
+ }
package/src/mcp/audit.js CHANGED
@@ -82,6 +82,11 @@ async function _postRemote(url, entry) {
82
82
  export function auditCall({ sessionRoot, tool, args, outcome, reason }) {
83
83
  if (!sessionRoot) return;
84
84
  try {
85
+ // Safety: only write audit log if sessionRoot looks like a project root
86
+ const MARKERS = ['.git', 'package.json', 'pyproject.toml', 'go.mod', 'Cargo.toml', 'pom.xml', 'composer.json', 'Gemfile'];
87
+ let hasMarker = false;
88
+ for (const m of MARKERS) { try { if (fs.existsSync(path.join(sessionRoot, m))) { hasMarker = true; break; } } catch {} }
89
+ if (!hasMarker) return;
85
90
  const dir = path.join(sessionRoot, '.agentic-security');
86
91
  fs.mkdirSync(dir, { recursive: true });
87
92
  const logFile = path.join(dir, 'mcp-audit.log');
package/src/mcp/tools.js CHANGED
@@ -238,6 +238,8 @@ function _findById(scan, id) {
238
238
  if (!scan) return null;
239
239
  return (scan.findings || []).find(f => f.id === id)
240
240
  || (scan.secrets || []).find(f => f.id === id)
241
+ || (scan.supplyChain || []).find(f => f.id === id)
242
+ || (scan.logicVulns || []).find(f => f.id === id)
241
243
  || null;
242
244
  }
243
245
 
@@ -468,6 +470,19 @@ export const explain_finding = {
468
470
  confidence: f.confidence ?? null,
469
471
  hasReplacementFix: typeof f.fix?.replacement === 'string',
470
472
  integrity: status,
473
+ // Risk-signal passthrough so agents can decide priority without
474
+ // re-reading last-scan.json or re-fetching OSV/KEV/EPSS. compositeRisk
475
+ // is the canonical sort key; the other fields are its provenance.
476
+ compositeRisk: f.compositeRisk ?? null,
477
+ compositeRiskTier: f.compositeRiskTier ?? null,
478
+ compositeRiskFactors: Array.isArray(f.compositeRiskFactors) ? f.compositeRiskFactors : [],
479
+ exploitability: f.exploitability ?? null,
480
+ exploitabilityTier: f.exploitabilityTier ?? null,
481
+ mitigationVerdict: f.mitigationVerdict ?? null,
482
+ kev: !!(f.kev || f.kevListed || f.weaponized),
483
+ epssScore: typeof f.epssScore === 'number' ? f.epssScore : null,
484
+ epssPercentile: typeof f.epssPercentile === 'number' ? f.epssPercentile : null,
485
+ exploitedNow: !!f.exploitedNow,
471
486
  };
472
487
  },
473
488
  };
@@ -952,4 +967,78 @@ export const lookup_cve = {
952
967
  },
953
968
  };
954
969
 
955
- export const ALL_TOOLS = [scan_diff, query_taint, explain_finding, apply_fix, verify_fix, synthesize_fix, find_rule_module, append_scratchpad, read_scratchpad, append_agents_memory, read_agents_memory, lookup_cve];
970
+ // ─── synthesize_sca_upgrade ───────────────────────────────────────────────
971
+ // Phase 3 / Item 5 of the SCA improvement plan. Read-only counterpart to
972
+ // apply_sca_upgrade — produces a structured upgrade plan via the
973
+ // ecosystem's native --dry-run command. Safe to call any number of times.
974
+ let _scaUpgrade;
975
+ async function _getScaUpgrade() {
976
+ if (!_scaUpgrade) _scaUpgrade = await import('../posture/sca-upgrade.js');
977
+ return _scaUpgrade;
978
+ }
979
+ export const synthesize_sca_upgrade = {
980
+ name: 'synthesize_sca_upgrade',
981
+ description: 'Generate an upgrade plan for a single SCA finding. Runs the ecosystem dry-run (npm install --dry-run, pip install --dry-run, cargo update --dry-run). Returns { ecosystem, package, currentVersion, targetVersion, isBreaking, command, manifestFiles, dryRun, testCommand }. No writes.',
982
+ inputSchema: {
983
+ type: 'object',
984
+ additionalProperties: false,
985
+ properties: {
986
+ finding_id: { type: 'string', minLength: 1, maxLength: 256 },
987
+ },
988
+ required: ['finding_id'],
989
+ },
990
+ async handler({ finding_id }, ctx) {
991
+ const { scan, status } = _readLastScanVerified(ctx.sessionRoot, { allowUnsigned: true });
992
+ if (!scan) throw new Error(`No usable scan state (${status}).`);
993
+ const f = _findById(scan, finding_id);
994
+ if (!f) throw new Error(`Finding not found: ${finding_id}`);
995
+ if (f.type !== 'vulnerable_dep') {
996
+ return { _meta: META, ok: false, reason: 'finding is not an SCA vulnerable_dep — use synthesize_fix for SAST findings' };
997
+ }
998
+ const { planScaUpgrade } = await _getScaUpgrade();
999
+ const plan = await planScaUpgrade({ scanRoot: ctx.sessionRoot, finding: f });
1000
+ return { _meta: META, ...plan };
1001
+ },
1002
+ };
1003
+
1004
+ // ─── apply_sca_upgrade ────────────────────────────────────────────────────
1005
+ // Phase 3 / Item 5 of the SCA improvement plan. The MCP `apply_fix` path
1006
+ // refuses every package-manager manifest by design. This tool bypasses
1007
+ // that ONLY for the install pathway — it shells out to the ecosystem's
1008
+ // native package manager (npm / pip / cargo / go) which is the right
1009
+ // surface for safely modifying manifests + lockfiles. Backs up affected
1010
+ // manifests before the install; runs the project's test command (if
1011
+ // detected); rolls back manifests if tests fail.
1012
+ export const apply_sca_upgrade = {
1013
+ name: 'apply_sca_upgrade',
1014
+ description: 'Apply a vulnerable_dep upgrade. Backs up manifests, runs the package manager, runs the project test command, restores manifests on test failure. Requires confirm:true. Set run_tests:false to skip the test gate (NOT recommended).',
1015
+ inputSchema: {
1016
+ type: 'object',
1017
+ additionalProperties: false,
1018
+ properties: {
1019
+ finding_id: { type: 'string', minLength: 1, maxLength: 256 },
1020
+ confirm: { type: 'boolean' },
1021
+ run_tests: { type: 'boolean' },
1022
+ },
1023
+ required: ['finding_id', 'confirm'],
1024
+ },
1025
+ async handler({ finding_id, confirm, run_tests = true }, ctx) {
1026
+ if (confirm !== true) {
1027
+ return { _meta: META, applied: false, reason: 'apply_sca_upgrade requires confirm: true.' };
1028
+ }
1029
+ const { scan, status } = _readLastScanVerified(ctx.sessionRoot, { allowUnsigned: false });
1030
+ if (!scan) {
1031
+ return { _meta: META, applied: false, reason: `last-scan.json failed integrity check: ${status}. Run a fresh scan.` };
1032
+ }
1033
+ const f = _findById(scan, finding_id);
1034
+ if (!f) return { _meta: META, applied: false, reason: `Finding not found: ${finding_id}` };
1035
+ if (f.type !== 'vulnerable_dep') {
1036
+ return { _meta: META, applied: false, reason: 'finding is not an SCA vulnerable_dep — use apply_fix for SAST findings' };
1037
+ }
1038
+ const { applyScaUpgrade } = await _getScaUpgrade();
1039
+ const result = await applyScaUpgrade({ scanRoot: ctx.sessionRoot, finding: f, runTests: run_tests });
1040
+ return { _meta: META, ...result };
1041
+ },
1042
+ };
1043
+
1044
+ export const ALL_TOOLS = [scan_diff, query_taint, explain_finding, apply_fix, verify_fix, synthesize_fix, find_rule_module, append_scratchpad, read_scratchpad, append_agents_memory, read_agents_memory, lookup_cve, synthesize_sca_upgrade, apply_sca_upgrade];