nexus-agents 2.29.0 → 2.29.1
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/adaptive-memory-RST6DZYR.js +15 -0
- package/dist/chunk-2UR7YN6T.js +700 -0
- package/dist/chunk-2UR7YN6T.js.map +1 -0
- package/dist/{chunk-KGDG6PWZ.js → chunk-2UUUKVNR.js} +2 -2
- package/dist/{chunk-5VZLXMO7.js → chunk-3EVVQ32X.js} +6 -6
- package/dist/{chunk-WSK4VSXP.js → chunk-3GXDN4AX.js} +2 -2
- package/dist/{chunk-ZBZJHXRT.js → chunk-4AGPR6XZ.js} +19 -347
- package/dist/chunk-4AGPR6XZ.js.map +1 -0
- package/dist/{chunk-7F6HYUIY.js → chunk-4HA5PAL7.js} +16 -97
- package/dist/chunk-4HA5PAL7.js.map +1 -0
- package/dist/chunk-7SKAKA4I.js +90 -0
- package/dist/chunk-7SKAKA4I.js.map +1 -0
- package/dist/chunk-AP2FD37C.js +127 -0
- package/dist/chunk-AP2FD37C.js.map +1 -0
- package/dist/chunk-BC3M4VLP.js +359 -0
- package/dist/chunk-BC3M4VLP.js.map +1 -0
- package/dist/chunk-BQ4YXGGQ.js +127 -0
- package/dist/chunk-BQ4YXGGQ.js.map +1 -0
- package/dist/chunk-C2C5ONFR.js +195 -0
- package/dist/chunk-C2C5ONFR.js.map +1 -0
- package/dist/{chunk-S3BKWNST.js → chunk-CGWRJ4EM.js} +614 -1428
- package/dist/chunk-CGWRJ4EM.js.map +1 -0
- package/dist/chunk-ED6VQWNG.js +63 -0
- package/dist/chunk-ED6VQWNG.js.map +1 -0
- package/dist/{chunk-IMWYKX4H.js → chunk-ELIFTCYM.js} +443 -398
- package/dist/chunk-ELIFTCYM.js.map +1 -0
- package/dist/chunk-FYJVXQHX.js +944 -0
- package/dist/chunk-FYJVXQHX.js.map +1 -0
- package/dist/{chunk-DAMRMAM2.js → chunk-FZFZ77UJ.js} +12127 -14458
- package/dist/chunk-FZFZ77UJ.js.map +1 -0
- package/dist/chunk-IECE6DBS.js +1585 -0
- package/dist/chunk-IECE6DBS.js.map +1 -0
- package/dist/chunk-LLGUX44Z.js +356 -0
- package/dist/chunk-LLGUX44Z.js.map +1 -0
- package/dist/chunk-MRU6L7YJ.js +931 -0
- package/dist/chunk-MRU6L7YJ.js.map +1 -0
- package/dist/{chunk-T7PU3NPQ.js → chunk-N5SY7V45.js} +7 -5
- package/dist/{chunk-T7PU3NPQ.js.map → chunk-N5SY7V45.js.map} +1 -1
- package/dist/{chunk-POBO4G2P.js → chunk-OOIPRRPX.js} +100 -10
- package/dist/chunk-OOIPRRPX.js.map +1 -0
- package/dist/{chunk-I6YDS23R.js → chunk-SRECH7OQ.js} +2 -2
- package/dist/{chunk-HH5LVGEE.js → chunk-VKRMXD62.js} +4 -4
- package/dist/{chunk-HWDBNDUX.js → chunk-XU3NADFE.js} +2 -2
- package/dist/chunk-YSTJEMQX.js +122 -0
- package/dist/chunk-YSTJEMQX.js.map +1 -0
- package/dist/cli-circuit-breaker-5FAODXVY.js +13 -0
- package/dist/cli.js +118 -67
- package/dist/cli.js.map +1 -1
- package/dist/codebase-search-CZUA37RU.js +9 -0
- package/dist/{composite-router-YPRWVTRB.js → composite-router-FNW7ZWL7.js} +2 -2
- package/dist/{consensus-vote-DBE6RNZG.js → consensus-vote-757YULIP.js} +7 -5
- package/dist/{dist-7PQR2BQB.js → dist-CV74KUT7.js} +1302 -805
- package/dist/dist-CV74KUT7.js.map +1 -0
- package/dist/{doctor-deep-AWE7SRU6.js → doctor-deep-LMCEAFU4.js} +3 -3
- package/dist/expert-bridge-L2D4OXOR.js +10 -0
- package/dist/{expert-config-FHNBQRX2.js → expert-config-A5CHKUGI.js} +2 -2
- package/dist/{factory-PCHGQ3ZG.js → factory-ELEDP2WD.js} +4 -3
- package/dist/{factory-O5C7ZBZO.js → factory-IDTIBX6B.js} +5 -4
- package/dist/index.d.ts +507 -42
- package/dist/index.js +331 -78
- package/dist/index.js.map +1 -1
- package/dist/issue-triage-SJPKJLXH.js +15 -0
- package/dist/{mcp-config-AUZQPUBY.js → mcp-config-2OXIOMJ6.js} +3 -3
- package/dist/mobimem-5S3VLNSU.js +13 -0
- package/dist/mobimem-5S3VLNSU.js.map +1 -0
- package/dist/repo-analyze-HWMXSK5C.js +24 -0
- package/dist/repo-analyze-HWMXSK5C.js.map +1 -0
- package/dist/repo-security-plan-MUFDGWSQ.js +17 -0
- package/dist/repo-security-plan-MUFDGWSQ.js.map +1 -0
- package/dist/research-helpers-synthesize-OBQJ5BGX.js +10 -0
- package/dist/research-helpers-synthesize-OBQJ5BGX.js.map +1 -0
- package/dist/{routing-memory-QY3XMU2R.js → routing-memory-3QBQTS4A.js} +2 -2
- package/dist/routing-memory-3QBQTS4A.js.map +1 -0
- package/dist/{session-memory-3MBCE5KS.js → session-memory-VXWLOFRC.js} +3 -3
- package/dist/session-memory-VXWLOFRC.js.map +1 -0
- package/dist/{setup-command-IQ4MD3FT.js → setup-command-E6MXO5RZ.js} +7 -6
- package/dist/setup-command-E6MXO5RZ.js.map +1 -0
- package/dist/{setup-config-5YUPLDXF.js → setup-config-O5F3AZBL.js} +3 -3
- package/dist/setup-config-O5F3AZBL.js.map +1 -0
- package/dist/shared-memory-AEO2HJLC.js +8 -0
- package/dist/shared-memory-AEO2HJLC.js.map +1 -0
- package/dist/symbol-extractor-UEBANFSN.js +10 -0
- package/dist/symbol-extractor-UEBANFSN.js.map +1 -0
- package/dist/{weather-report-CC2C4KAX.js → weather-report-MUGSIOU5.js} +2 -2
- package/dist/weather-report-MUGSIOU5.js.map +1 -0
- package/package.json +14 -13
- package/dist/chunk-7F6HYUIY.js.map +0 -1
- package/dist/chunk-DAMRMAM2.js.map +0 -1
- package/dist/chunk-IMWYKX4H.js.map +0 -1
- package/dist/chunk-POBO4G2P.js.map +0 -1
- package/dist/chunk-S3BKWNST.js.map +0 -1
- package/dist/chunk-ZBZJHXRT.js.map +0 -1
- package/dist/dist-7PQR2BQB.js.map +0 -1
- /package/dist/{composite-router-YPRWVTRB.js.map → adaptive-memory-RST6DZYR.js.map} +0 -0
- /package/dist/{chunk-KGDG6PWZ.js.map → chunk-2UUUKVNR.js.map} +0 -0
- /package/dist/{chunk-5VZLXMO7.js.map → chunk-3EVVQ32X.js.map} +0 -0
- /package/dist/{chunk-WSK4VSXP.js.map → chunk-3GXDN4AX.js.map} +0 -0
- /package/dist/{chunk-I6YDS23R.js.map → chunk-SRECH7OQ.js.map} +0 -0
- /package/dist/{chunk-HH5LVGEE.js.map → chunk-VKRMXD62.js.map} +0 -0
- /package/dist/{chunk-HWDBNDUX.js.map → chunk-XU3NADFE.js.map} +0 -0
- /package/dist/{consensus-vote-DBE6RNZG.js.map → cli-circuit-breaker-5FAODXVY.js.map} +0 -0
- /package/dist/{doctor-deep-AWE7SRU6.js.map → codebase-search-CZUA37RU.js.map} +0 -0
- /package/dist/{expert-config-FHNBQRX2.js.map → composite-router-FNW7ZWL7.js.map} +0 -0
- /package/dist/{factory-O5C7ZBZO.js.map → consensus-vote-757YULIP.js.map} +0 -0
- /package/dist/{factory-PCHGQ3ZG.js.map → doctor-deep-LMCEAFU4.js.map} +0 -0
- /package/dist/{mcp-config-AUZQPUBY.js.map → expert-bridge-L2D4OXOR.js.map} +0 -0
- /package/dist/{routing-memory-QY3XMU2R.js.map → expert-config-A5CHKUGI.js.map} +0 -0
- /package/dist/{session-memory-3MBCE5KS.js.map → factory-ELEDP2WD.js.map} +0 -0
- /package/dist/{setup-command-IQ4MD3FT.js.map → factory-IDTIBX6B.js.map} +0 -0
- /package/dist/{setup-config-5YUPLDXF.js.map → issue-triage-SJPKJLXH.js.map} +0 -0
- /package/dist/{weather-report-CC2C4KAX.js.map → mcp-config-2OXIOMJ6.js.map} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AdaptiveMemoryBackend,
|
|
3
|
+
DEFAULT_SCORING_CONFIG,
|
|
4
|
+
createAdaptiveMemory
|
|
5
|
+
} from "./chunk-FYJVXQHX.js";
|
|
6
|
+
import "./chunk-633WH2ML.js";
|
|
7
|
+
import "./chunk-ELIFTCYM.js";
|
|
8
|
+
import "./chunk-CLYZ7FWP.js";
|
|
9
|
+
import "./chunk-UP2VWCW5.js";
|
|
10
|
+
export {
|
|
11
|
+
AdaptiveMemoryBackend,
|
|
12
|
+
DEFAULT_SCORING_CONFIG,
|
|
13
|
+
createAdaptiveMemory
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=adaptive-memory-RST6DZYR.js.map
|
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzeGitHubRepo
|
|
3
|
+
} from "./chunk-BC3M4VLP.js";
|
|
4
|
+
import {
|
|
5
|
+
createLogger
|
|
6
|
+
} from "./chunk-ELIFTCYM.js";
|
|
7
|
+
|
|
8
|
+
// src/mcp/tools/scanner-registry-fetcher.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var RelationshipSchema = z.object({
|
|
11
|
+
target: z.string().min(1),
|
|
12
|
+
type: z.enum(["uses", "supersedes", "bundles", "competes-with"])
|
|
13
|
+
});
|
|
14
|
+
var ScannerSchema = z.object({
|
|
15
|
+
name: z.string().min(1),
|
|
16
|
+
displayName: z.string().min(1),
|
|
17
|
+
categories: z.array(z.string().min(1)),
|
|
18
|
+
license: z.string().min(1),
|
|
19
|
+
pricingModel: z.string().min(1),
|
|
20
|
+
relationships: z.array(RelationshipSchema).optional()
|
|
21
|
+
});
|
|
22
|
+
var LanguageMatrixEntrySchema = z.object({
|
|
23
|
+
sast: z.array(z.string()).optional(),
|
|
24
|
+
sca: z.array(z.string()).optional(),
|
|
25
|
+
secrets: z.array(z.string()).optional(),
|
|
26
|
+
container: z.array(z.string()).optional(),
|
|
27
|
+
iac: z.array(z.string()).optional(),
|
|
28
|
+
dast: z.array(z.string()).optional()
|
|
29
|
+
}).loose();
|
|
30
|
+
var ManifestSchema = z.object({
|
|
31
|
+
version: z.string().min(1),
|
|
32
|
+
generatedAt: z.string().min(1),
|
|
33
|
+
scanners: z.array(ScannerSchema),
|
|
34
|
+
languageMatrix: z.record(z.string().max(50), LanguageMatrixEntrySchema)
|
|
35
|
+
});
|
|
36
|
+
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
37
|
+
var cachedEntry = null;
|
|
38
|
+
var inflightFetch;
|
|
39
|
+
function clearRegistryCache() {
|
|
40
|
+
cachedEntry = null;
|
|
41
|
+
inflightFetch = void 0;
|
|
42
|
+
}
|
|
43
|
+
var REGISTRY_REPO = "williamzujkowski/vulnerability-scanner-registry";
|
|
44
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
45
|
+
var logger = createLogger({ component: "scanner-registry-fetcher" });
|
|
46
|
+
async function getLatestReleaseTag(execFileAsync) {
|
|
47
|
+
const { stdout } = await execFileAsync(
|
|
48
|
+
"gh",
|
|
49
|
+
["release", "view", "--repo", REGISTRY_REPO, "--json", "tagName", "--jq", ".tagName"],
|
|
50
|
+
{ timeout: FETCH_TIMEOUT_MS }
|
|
51
|
+
);
|
|
52
|
+
return stdout.trim() || null;
|
|
53
|
+
}
|
|
54
|
+
async function downloadManifest(execFileAsync) {
|
|
55
|
+
const { stdout } = await execFileAsync(
|
|
56
|
+
"gh",
|
|
57
|
+
[
|
|
58
|
+
"release",
|
|
59
|
+
"download",
|
|
60
|
+
"--repo",
|
|
61
|
+
REGISTRY_REPO,
|
|
62
|
+
"--pattern",
|
|
63
|
+
"scanner-registry.json",
|
|
64
|
+
"--output",
|
|
65
|
+
"-"
|
|
66
|
+
],
|
|
67
|
+
{ timeout: FETCH_TIMEOUT_MS, maxBuffer: 1024 * 1024 }
|
|
68
|
+
);
|
|
69
|
+
let jsonData;
|
|
70
|
+
try {
|
|
71
|
+
jsonData = JSON.parse(stdout);
|
|
72
|
+
} catch {
|
|
73
|
+
logger.warn("Registry manifest is not valid JSON", {
|
|
74
|
+
stdoutLength: stdout.length,
|
|
75
|
+
preview: stdout.slice(0, 100)
|
|
76
|
+
});
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const parsed = ManifestSchema.safeParse(jsonData);
|
|
80
|
+
if (!parsed.success) {
|
|
81
|
+
logger.warn("Registry manifest failed schema validation", {
|
|
82
|
+
errors: parsed.error.issues.slice(0, 3)
|
|
83
|
+
});
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
logger.info("Fetched scanner registry manifest", {
|
|
87
|
+
version: parsed.data.version,
|
|
88
|
+
scanners: parsed.data.scanners.length,
|
|
89
|
+
languages: Object.keys(parsed.data.languageMatrix).length
|
|
90
|
+
});
|
|
91
|
+
return parsed.data;
|
|
92
|
+
}
|
|
93
|
+
async function fetchManifestFromGitHub() {
|
|
94
|
+
try {
|
|
95
|
+
const { execFile } = await import("child_process");
|
|
96
|
+
const { promisify } = await import("util");
|
|
97
|
+
const execFileAsync = promisify(execFile);
|
|
98
|
+
const tag = await getLatestReleaseTag(execFileAsync);
|
|
99
|
+
if (tag === null) {
|
|
100
|
+
logger.warn("No releases found in scanner registry");
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (cachedEntry !== null && cachedEntry.releaseTag === tag) {
|
|
104
|
+
logger.debug("Scanner registry unchanged, refreshing cache timer", { tag });
|
|
105
|
+
cachedEntry = { ...cachedEntry, fetchedAt: Date.now() };
|
|
106
|
+
return cachedEntry.manifest;
|
|
107
|
+
}
|
|
108
|
+
const manifest = await downloadManifest(execFileAsync);
|
|
109
|
+
if (manifest !== null) {
|
|
110
|
+
cachedEntry = { manifest, fetchedAt: Date.now(), releaseTag: tag };
|
|
111
|
+
}
|
|
112
|
+
return manifest;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
115
|
+
logger.debug("Failed to fetch scanner registry", { error: msg });
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function getRegistryManifest() {
|
|
120
|
+
if (cachedEntry !== null) {
|
|
121
|
+
const age = Date.now() - cachedEntry.fetchedAt;
|
|
122
|
+
if (age < CACHE_TTL_MS) {
|
|
123
|
+
return cachedEntry.manifest;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
inflightFetch ??= fetchManifestFromGitHub().finally(() => {
|
|
127
|
+
inflightFetch = void 0;
|
|
128
|
+
});
|
|
129
|
+
const manifest = await inflightFetch;
|
|
130
|
+
if (manifest !== null) {
|
|
131
|
+
return manifest;
|
|
132
|
+
}
|
|
133
|
+
if (cachedEntry !== null) {
|
|
134
|
+
logger.warn("Using stale cached registry manifest");
|
|
135
|
+
return cachedEntry.manifest;
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/mcp/tools/repo-security-plan-fallback.ts
|
|
141
|
+
var FALLBACK_SCANNERS = [
|
|
142
|
+
{
|
|
143
|
+
name: "semgrep",
|
|
144
|
+
displayName: "Semgrep",
|
|
145
|
+
categories: ["sast", "secrets"],
|
|
146
|
+
license: "LGPL-2.1",
|
|
147
|
+
pricingModel: "freemium"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "codeql",
|
|
151
|
+
displayName: "CodeQL",
|
|
152
|
+
categories: ["sast"],
|
|
153
|
+
license: "MIT",
|
|
154
|
+
pricingModel: "freemium"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "bandit",
|
|
158
|
+
displayName: "Bandit",
|
|
159
|
+
categories: ["sast"],
|
|
160
|
+
license: "Apache-2.0",
|
|
161
|
+
pricingModel: "free"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "gosec",
|
|
165
|
+
displayName: "Gosec",
|
|
166
|
+
categories: ["sast"],
|
|
167
|
+
license: "Apache-2.0",
|
|
168
|
+
pricingModel: "free"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: "brakeman",
|
|
172
|
+
displayName: "Brakeman",
|
|
173
|
+
categories: ["sast"],
|
|
174
|
+
license: "MIT",
|
|
175
|
+
pricingModel: "free"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "phpstan",
|
|
179
|
+
displayName: "PHPStan",
|
|
180
|
+
categories: ["sast"],
|
|
181
|
+
license: "MIT",
|
|
182
|
+
pricingModel: "freemium"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "shellcheck",
|
|
186
|
+
displayName: "ShellCheck",
|
|
187
|
+
categories: ["sast"],
|
|
188
|
+
license: "GPL-3.0",
|
|
189
|
+
pricingModel: "free"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "cppcheck",
|
|
193
|
+
displayName: "Cppcheck",
|
|
194
|
+
categories: ["sast"],
|
|
195
|
+
license: "GPL-3.0",
|
|
196
|
+
pricingModel: "free"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "detekt",
|
|
200
|
+
displayName: "detekt",
|
|
201
|
+
categories: ["sast"],
|
|
202
|
+
license: "Apache-2.0",
|
|
203
|
+
pricingModel: "free"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: "spotbugs",
|
|
207
|
+
displayName: "SpotBugs",
|
|
208
|
+
categories: ["sast"],
|
|
209
|
+
license: "LGPL-2.1",
|
|
210
|
+
pricingModel: "free"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: "eslint-security",
|
|
214
|
+
displayName: "eslint-plugin-security",
|
|
215
|
+
categories: ["sast"],
|
|
216
|
+
license: "Apache-2.0",
|
|
217
|
+
pricingModel: "free"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "sonarqube",
|
|
221
|
+
displayName: "SonarQube",
|
|
222
|
+
categories: ["sast", "sca"],
|
|
223
|
+
license: "LGPL-3.0",
|
|
224
|
+
pricingModel: "freemium"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "osv-scanner",
|
|
228
|
+
displayName: "OSV-Scanner",
|
|
229
|
+
categories: ["sca", "container", "iac", "sbom"],
|
|
230
|
+
license: "Apache-2.0",
|
|
231
|
+
pricingModel: "free"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: "grype",
|
|
235
|
+
displayName: "Grype",
|
|
236
|
+
categories: ["sca", "container"],
|
|
237
|
+
license: "Apache-2.0",
|
|
238
|
+
pricingModel: "free"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "snyk",
|
|
242
|
+
displayName: "Snyk",
|
|
243
|
+
categories: ["sca", "sast", "container"],
|
|
244
|
+
license: "Proprietary",
|
|
245
|
+
pricingModel: "freemium"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "npm-audit",
|
|
249
|
+
displayName: "npm audit",
|
|
250
|
+
categories: ["sca"],
|
|
251
|
+
license: "Artistic-2.0",
|
|
252
|
+
pricingModel: "free"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: "pip-audit",
|
|
256
|
+
displayName: "pip-audit",
|
|
257
|
+
categories: ["sca"],
|
|
258
|
+
license: "Apache-2.0",
|
|
259
|
+
pricingModel: "free"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "cargo-audit",
|
|
263
|
+
displayName: "cargo-audit",
|
|
264
|
+
categories: ["sca"],
|
|
265
|
+
license: "Apache-2.0",
|
|
266
|
+
pricingModel: "free"
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: "bundler-audit",
|
|
270
|
+
displayName: "bundler-audit",
|
|
271
|
+
categories: ["sca"],
|
|
272
|
+
license: "GPL-3.0",
|
|
273
|
+
pricingModel: "free"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "govulncheck",
|
|
277
|
+
displayName: "govulncheck",
|
|
278
|
+
categories: ["sca"],
|
|
279
|
+
license: "BSD-3-Clause",
|
|
280
|
+
pricingModel: "free"
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: "owasp-dependency-check",
|
|
284
|
+
displayName: "OWASP Dependency-Check",
|
|
285
|
+
categories: ["sca"],
|
|
286
|
+
license: "Apache-2.0",
|
|
287
|
+
pricingModel: "free"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: "gitleaks",
|
|
291
|
+
displayName: "Gitleaks",
|
|
292
|
+
categories: ["secrets"],
|
|
293
|
+
license: "MIT",
|
|
294
|
+
pricingModel: "free"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "trufflehog",
|
|
298
|
+
displayName: "TruffleHog",
|
|
299
|
+
categories: ["secrets"],
|
|
300
|
+
license: "AGPL-3.0",
|
|
301
|
+
pricingModel: "freemium"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "checkov",
|
|
305
|
+
displayName: "Checkov",
|
|
306
|
+
categories: ["iac", "sca"],
|
|
307
|
+
license: "Apache-2.0",
|
|
308
|
+
pricingModel: "free"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: "tfsec",
|
|
312
|
+
displayName: "tfsec",
|
|
313
|
+
categories: ["iac"],
|
|
314
|
+
license: "MIT",
|
|
315
|
+
pricingModel: "free"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: "owasp-zap",
|
|
319
|
+
displayName: "OWASP ZAP",
|
|
320
|
+
categories: ["dast", "api"],
|
|
321
|
+
license: "Apache-2.0",
|
|
322
|
+
pricingModel: "free"
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: "syft",
|
|
326
|
+
displayName: "Syft",
|
|
327
|
+
categories: ["sbom"],
|
|
328
|
+
license: "Apache-2.0",
|
|
329
|
+
pricingModel: "free"
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: "grype-image",
|
|
333
|
+
displayName: "Grype (image scan)",
|
|
334
|
+
categories: ["image-currency", "container"],
|
|
335
|
+
license: "Apache-2.0",
|
|
336
|
+
pricingModel: "free"
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
var FALLBACK_LANGUAGE_MAP = {
|
|
340
|
+
TypeScript: {
|
|
341
|
+
sast: ["semgrep", "eslint-security", "codeql"],
|
|
342
|
+
sca: ["npm-audit", "osv-scanner"],
|
|
343
|
+
secrets: ["gitleaks"]
|
|
344
|
+
},
|
|
345
|
+
JavaScript: {
|
|
346
|
+
sast: ["semgrep", "eslint-security", "codeql"],
|
|
347
|
+
sca: ["npm-audit", "osv-scanner"],
|
|
348
|
+
secrets: ["gitleaks"]
|
|
349
|
+
},
|
|
350
|
+
Python: {
|
|
351
|
+
sast: ["bandit", "semgrep", "codeql"],
|
|
352
|
+
sca: ["pip-audit", "osv-scanner"],
|
|
353
|
+
secrets: ["gitleaks"]
|
|
354
|
+
},
|
|
355
|
+
Java: {
|
|
356
|
+
sast: ["codeql", "semgrep", "spotbugs"],
|
|
357
|
+
sca: ["owasp-dependency-check", "osv-scanner"],
|
|
358
|
+
secrets: ["gitleaks"]
|
|
359
|
+
},
|
|
360
|
+
Go: {
|
|
361
|
+
sast: ["gosec", "semgrep", "codeql"],
|
|
362
|
+
sca: ["govulncheck", "osv-scanner"],
|
|
363
|
+
secrets: ["gitleaks"]
|
|
364
|
+
},
|
|
365
|
+
Ruby: {
|
|
366
|
+
sast: ["brakeman", "semgrep", "codeql"],
|
|
367
|
+
sca: ["bundler-audit", "osv-scanner"],
|
|
368
|
+
secrets: ["gitleaks"]
|
|
369
|
+
},
|
|
370
|
+
PHP: {
|
|
371
|
+
sast: ["phpstan", "semgrep"],
|
|
372
|
+
sca: ["osv-scanner"],
|
|
373
|
+
secrets: ["gitleaks"]
|
|
374
|
+
},
|
|
375
|
+
"C#": {
|
|
376
|
+
sast: ["codeql", "semgrep"],
|
|
377
|
+
sca: ["osv-scanner"],
|
|
378
|
+
secrets: ["gitleaks"]
|
|
379
|
+
},
|
|
380
|
+
C: {
|
|
381
|
+
sast: ["cppcheck", "codeql", "semgrep"],
|
|
382
|
+
sca: ["osv-scanner"],
|
|
383
|
+
secrets: ["gitleaks"]
|
|
384
|
+
},
|
|
385
|
+
"C++": {
|
|
386
|
+
sast: ["cppcheck", "codeql", "semgrep"],
|
|
387
|
+
sca: ["osv-scanner"],
|
|
388
|
+
secrets: ["gitleaks"]
|
|
389
|
+
},
|
|
390
|
+
Rust: {
|
|
391
|
+
sast: ["semgrep"],
|
|
392
|
+
sca: ["cargo-audit", "osv-scanner"],
|
|
393
|
+
secrets: ["gitleaks"]
|
|
394
|
+
},
|
|
395
|
+
Kotlin: {
|
|
396
|
+
sast: ["detekt", "semgrep", "codeql"],
|
|
397
|
+
sca: ["osv-scanner"],
|
|
398
|
+
secrets: ["gitleaks"]
|
|
399
|
+
},
|
|
400
|
+
Swift: {
|
|
401
|
+
sast: ["codeql", "semgrep"],
|
|
402
|
+
sca: ["osv-scanner"],
|
|
403
|
+
secrets: ["gitleaks"]
|
|
404
|
+
},
|
|
405
|
+
Scala: {
|
|
406
|
+
sast: ["semgrep", "spotbugs"],
|
|
407
|
+
sca: ["osv-scanner"],
|
|
408
|
+
secrets: ["gitleaks"]
|
|
409
|
+
},
|
|
410
|
+
Shell: {
|
|
411
|
+
sast: ["shellcheck", "semgrep"],
|
|
412
|
+
sca: [],
|
|
413
|
+
secrets: ["gitleaks"]
|
|
414
|
+
},
|
|
415
|
+
HCL: {
|
|
416
|
+
sast: ["checkov", "tfsec"],
|
|
417
|
+
sca: ["osv-scanner"],
|
|
418
|
+
secrets: ["gitleaks"]
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
var FALLBACK_SCANNER_DATA = {
|
|
422
|
+
scanners: FALLBACK_SCANNERS,
|
|
423
|
+
languageMap: FALLBACK_LANGUAGE_MAP,
|
|
424
|
+
source: "fallback"
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// src/mcp/tools/repo-security-plan.ts
|
|
428
|
+
var logger2 = createLogger({ component: "repo-security-plan" });
|
|
429
|
+
function convertRegistryScanner(s) {
|
|
430
|
+
const supersedes = s.relationships?.filter((r) => r.type === "supersedes").map((r) => r.target);
|
|
431
|
+
return {
|
|
432
|
+
name: s.name,
|
|
433
|
+
displayName: s.displayName,
|
|
434
|
+
categories: s.categories,
|
|
435
|
+
license: s.license,
|
|
436
|
+
pricingModel: s.pricingModel,
|
|
437
|
+
...supersedes !== void 0 && supersedes.length > 0 ? { supersedes } : {}
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
var LANGUAGE_PASCAL_MAP = {
|
|
441
|
+
typescript: "TypeScript",
|
|
442
|
+
javascript: "JavaScript",
|
|
443
|
+
python: "Python",
|
|
444
|
+
java: "Java",
|
|
445
|
+
csharp: "C#",
|
|
446
|
+
"c#": "C#",
|
|
447
|
+
cpp: "C++",
|
|
448
|
+
"c++": "C++",
|
|
449
|
+
go: "Go",
|
|
450
|
+
rust: "Rust",
|
|
451
|
+
ruby: "Ruby",
|
|
452
|
+
php: "PHP",
|
|
453
|
+
swift: "Swift",
|
|
454
|
+
kotlin: "Kotlin",
|
|
455
|
+
scala: "Scala",
|
|
456
|
+
hcl: "HCL",
|
|
457
|
+
shell: "Shell",
|
|
458
|
+
dockerfile: "Dockerfile"
|
|
459
|
+
};
|
|
460
|
+
function normalizeLangName(lang) {
|
|
461
|
+
const lower = lang.toLowerCase();
|
|
462
|
+
return LANGUAGE_PASCAL_MAP[lower] ?? lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
463
|
+
}
|
|
464
|
+
function convertLanguageMatrix(matrix) {
|
|
465
|
+
const result = {};
|
|
466
|
+
for (const [lang, entry] of Object.entries(matrix)) {
|
|
467
|
+
const normalized = normalizeLangName(lang);
|
|
468
|
+
result[normalized] = {
|
|
469
|
+
sast: entry.sast ?? [],
|
|
470
|
+
sca: entry.sca ?? [],
|
|
471
|
+
secrets: entry.secrets ?? []
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
async function resolveScannerData() {
|
|
477
|
+
const manifest = await getRegistryManifest();
|
|
478
|
+
if (manifest !== null) {
|
|
479
|
+
logger2.info("Using live scanner registry", {
|
|
480
|
+
version: manifest.version,
|
|
481
|
+
scanners: manifest.scanners.length
|
|
482
|
+
});
|
|
483
|
+
return {
|
|
484
|
+
scanners: manifest.scanners.map(convertRegistryScanner),
|
|
485
|
+
languageMap: convertLanguageMatrix(manifest.languageMatrix),
|
|
486
|
+
source: "registry"
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
logger2.info("Using fallback scanner data");
|
|
490
|
+
return FALLBACK_SCANNER_DATA;
|
|
491
|
+
}
|
|
492
|
+
var CI_SNIPPETS = {
|
|
493
|
+
semgrep: "- uses: semgrep/semgrep-action@v1\n with:\n config: auto",
|
|
494
|
+
codeql: "- uses: github/codeql-action/analyze@v3",
|
|
495
|
+
grype: "- uses: anchore/scan-action@v4\n with:\n path: .",
|
|
496
|
+
"grype-image": "- uses: anchore/scan-action@v4\n with:\n image: ${{ env.IMAGE_TAG }}\n severity: CRITICAL,HIGH\n exit-code: 1",
|
|
497
|
+
gitleaks: "- uses: gitleaks/gitleaks-action@v2",
|
|
498
|
+
bandit: "- run: pip install bandit && bandit -r . -f json",
|
|
499
|
+
gosec: "- uses: securego/gosec@master\n with:\n args: ./...",
|
|
500
|
+
checkov: "- uses: bridgecrewio/checkov-action@master",
|
|
501
|
+
"osv-scanner": "- uses: google/osv-scanner-action@v1",
|
|
502
|
+
snyk: "- uses: snyk/actions/node@master # adjust for language",
|
|
503
|
+
shellcheck: "- uses: ludeeus/action-shellcheck@master"
|
|
504
|
+
};
|
|
505
|
+
function generateCiSnippet(name, ci) {
|
|
506
|
+
if (ci !== "github-actions") return null;
|
|
507
|
+
return CI_SNIPPETS[name] ?? null;
|
|
508
|
+
}
|
|
509
|
+
function findScanner(name, scanners) {
|
|
510
|
+
return scanners.find((s) => s.name === name);
|
|
511
|
+
}
|
|
512
|
+
function isAlreadyUsed(name, existing) {
|
|
513
|
+
return existing.some((t) => t.toLowerCase().includes(name.toLowerCase()));
|
|
514
|
+
}
|
|
515
|
+
function collectCategoryRecs(recs, opts) {
|
|
516
|
+
for (const name of opts.names) {
|
|
517
|
+
if (recs.length >= opts.ctx.maxScanners) break;
|
|
518
|
+
if (isAlreadyUsed(name, opts.ctx.existing)) continue;
|
|
519
|
+
const entry = findScanner(name, opts.ctx.scanners);
|
|
520
|
+
if (!entry) continue;
|
|
521
|
+
if (opts.ctx.categoryFilter && !opts.ctx.categoryFilter.has(opts.category)) continue;
|
|
522
|
+
const isFirst = opts.category === "sast" && recs.length === 0;
|
|
523
|
+
recs.push({
|
|
524
|
+
name,
|
|
525
|
+
displayName: entry.displayName,
|
|
526
|
+
category: opts.category,
|
|
527
|
+
license: entry.license,
|
|
528
|
+
pricingModel: entry.pricingModel,
|
|
529
|
+
rationale: opts.rationale(entry),
|
|
530
|
+
priority: isFirst ? "critical" : opts.priority,
|
|
531
|
+
ciSnippet: generateCiSnippet(name, opts.ctx.ciProvider)
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function collectLanguageRecs(langMap, recs, ctx) {
|
|
536
|
+
const lang = ctx.language ?? "unknown";
|
|
537
|
+
collectCategoryRecs(recs, {
|
|
538
|
+
names: langMap.sast,
|
|
539
|
+
category: "sast",
|
|
540
|
+
rationale: (e) => `${e.displayName} provides SAST for ${lang}`,
|
|
541
|
+
priority: "recommended",
|
|
542
|
+
ctx
|
|
543
|
+
});
|
|
544
|
+
collectCategoryRecs(recs, {
|
|
545
|
+
names: langMap.sca,
|
|
546
|
+
category: "sca",
|
|
547
|
+
rationale: (e) => `${e.displayName} provides SCA for ${lang} dependencies`,
|
|
548
|
+
priority: "critical",
|
|
549
|
+
ctx
|
|
550
|
+
});
|
|
551
|
+
collectCategoryRecs(recs, {
|
|
552
|
+
names: langMap.secrets,
|
|
553
|
+
category: "secrets",
|
|
554
|
+
rationale: () => "Detects leaked credentials and API keys in source code",
|
|
555
|
+
priority: "critical",
|
|
556
|
+
ctx
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
function tryAddScanner(scannerName, category, rationale, recs, ctx) {
|
|
560
|
+
if (recs.length >= ctx.maxScanners) return;
|
|
561
|
+
if (ctx.categoryFilter && !ctx.categoryFilter.has(category)) return;
|
|
562
|
+
if (isAlreadyUsed(scannerName, ctx.existing)) return;
|
|
563
|
+
if (recs.some((r) => r.name === scannerName)) return;
|
|
564
|
+
const entry = findScanner(scannerName, ctx.scanners);
|
|
565
|
+
if (!entry) return;
|
|
566
|
+
recs.push({
|
|
567
|
+
name: scannerName,
|
|
568
|
+
displayName: entry.displayName,
|
|
569
|
+
category,
|
|
570
|
+
license: entry.license,
|
|
571
|
+
pricingModel: entry.pricingModel,
|
|
572
|
+
rationale,
|
|
573
|
+
priority: "recommended",
|
|
574
|
+
ciSnippet: generateCiSnippet(scannerName, ctx.ciProvider)
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
function detectConflicts(recs, scanners) {
|
|
578
|
+
const warnings = [];
|
|
579
|
+
const names = new Set(recs.map((r) => r.name));
|
|
580
|
+
detectSuperseded(names, scanners, warnings);
|
|
581
|
+
detectRedundant(recs, warnings);
|
|
582
|
+
return warnings;
|
|
583
|
+
}
|
|
584
|
+
function detectSuperseded(names, scanners, warnings) {
|
|
585
|
+
for (const scanner of scanners) {
|
|
586
|
+
if (!names.has(scanner.name)) continue;
|
|
587
|
+
if (!scanner.supersedes) continue;
|
|
588
|
+
for (const old of scanner.supersedes) {
|
|
589
|
+
if (names.has(old)) {
|
|
590
|
+
warnings.push({
|
|
591
|
+
scanners: [old, scanner.name],
|
|
592
|
+
type: "superseded",
|
|
593
|
+
recommendation: `${scanner.displayName} supersedes ${old}. Remove ${old}.`
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function detectRedundant(recs, warnings) {
|
|
600
|
+
const catMap = /* @__PURE__ */ new Map();
|
|
601
|
+
for (const rec of recs) {
|
|
602
|
+
const arr = catMap.get(rec.category) ?? [];
|
|
603
|
+
arr.push(rec.name);
|
|
604
|
+
catMap.set(rec.category, arr);
|
|
605
|
+
}
|
|
606
|
+
for (const [cat, scanners] of catMap) {
|
|
607
|
+
if (scanners.length > 2) {
|
|
608
|
+
const count = String(scanners.length);
|
|
609
|
+
warnings.push({
|
|
610
|
+
scanners,
|
|
611
|
+
type: "redundant",
|
|
612
|
+
recommendation: `${count} scanners for ${cat}. Consider keeping top 2.`
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
var ALL_CATEGORIES = ["sast", "dast", "sca", "secrets", "container", "iac", "image-currency"];
|
|
618
|
+
function buildCoverage(recs, existing, scanners) {
|
|
619
|
+
return ALL_CATEGORIES.map((cat) => {
|
|
620
|
+
const found = recs.filter((r) => r.category === cat).map((r) => r.name);
|
|
621
|
+
const existingMatch = existing.some(
|
|
622
|
+
(t) => scanners.some((s) => s.categories.includes(cat) && t.toLowerCase().includes(s.name))
|
|
623
|
+
);
|
|
624
|
+
return { category: cat, covered: found.length > 0 || existingMatch, scanners: found };
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
async function generateSecurityPlan(input) {
|
|
628
|
+
const [analysis, data] = await Promise.all([
|
|
629
|
+
analyzeGitHubRepo({ repo: input.repo, depth: "deep" }),
|
|
630
|
+
resolveScannerData()
|
|
631
|
+
]);
|
|
632
|
+
return buildPlanFromAnalysis(analysis, input, data);
|
|
633
|
+
}
|
|
634
|
+
function collectInfraRecs(analysis, recs, ctx) {
|
|
635
|
+
if (analysis.hasDockerfile) {
|
|
636
|
+
tryAddScanner(
|
|
637
|
+
"grype",
|
|
638
|
+
"container",
|
|
639
|
+
"Dockerfile detected \u2014 scan container images for vulnerabilities",
|
|
640
|
+
recs,
|
|
641
|
+
ctx
|
|
642
|
+
);
|
|
643
|
+
tryAddScanner("grype-image", "image-currency", buildImageCurrencyRationale(), recs, ctx);
|
|
644
|
+
}
|
|
645
|
+
if (analysis.hasHelmCharts) {
|
|
646
|
+
tryAddScanner(
|
|
647
|
+
"checkov",
|
|
648
|
+
"iac",
|
|
649
|
+
"Helm charts detected \u2014 scan IaC for misconfigurations",
|
|
650
|
+
recs,
|
|
651
|
+
ctx
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
function buildImageCurrencyRationale() {
|
|
656
|
+
return "Dockerfile detected \u2014 periodically scan built images with `grype image --severity CRITICAL,HIGH` to detect CVEs introduced by stale base images. Pin base images to specific version tags (e.g., node:22.4.0-alpine3.20) rather than :latest to get reproducible scans and predictable CVE surface area. Alpine-based images typically have a smaller CVE surface than Debian/Ubuntu equivalents due to musl libc and a minimal package set, but verify with grype before assuming.";
|
|
657
|
+
}
|
|
658
|
+
function buildPlanFromAnalysis(analysis, input, data) {
|
|
659
|
+
const resolved = data ?? FALLBACK_SCANNER_DATA;
|
|
660
|
+
const ctx = {
|
|
661
|
+
existing: analysis.securityTooling,
|
|
662
|
+
ciProvider: analysis.ciProvider,
|
|
663
|
+
language: analysis.language,
|
|
664
|
+
categoryFilter: input.categories ? new Set(input.categories) : null,
|
|
665
|
+
maxScanners: input.maxScanners ?? 10,
|
|
666
|
+
scanners: resolved.scanners
|
|
667
|
+
};
|
|
668
|
+
const recs = [];
|
|
669
|
+
const normalizedLang = analysis.language !== null ? normalizeLangName(analysis.language) : null;
|
|
670
|
+
const langMap = normalizedLang !== null ? resolved.languageMap[normalizedLang] : void 0;
|
|
671
|
+
if (langMap) collectLanguageRecs(langMap, recs, ctx);
|
|
672
|
+
collectInfraRecs(analysis, recs, ctx);
|
|
673
|
+
const conflicts = detectConflicts(recs, resolved.scanners);
|
|
674
|
+
const coverage = buildCoverage(recs, analysis.securityTooling, resolved.scanners);
|
|
675
|
+
const uncovered = coverage.filter((c) => !c.covered).map((c) => c.category);
|
|
676
|
+
return {
|
|
677
|
+
repo: analysis.name,
|
|
678
|
+
language: analysis.language,
|
|
679
|
+
framework: analysis.framework,
|
|
680
|
+
ciProvider: analysis.ciProvider,
|
|
681
|
+
existingTooling: analysis.securityTooling,
|
|
682
|
+
recommendations: recs,
|
|
683
|
+
conflicts,
|
|
684
|
+
coverage,
|
|
685
|
+
gapsSummary: [
|
|
686
|
+
...analysis.gaps,
|
|
687
|
+
...uncovered.length > 0 ? [`Uncovered categories: ${uncovered.join(", ")}`] : []
|
|
688
|
+
]
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
export {
|
|
693
|
+
clearRegistryCache,
|
|
694
|
+
getRegistryManifest,
|
|
695
|
+
FALLBACK_SCANNER_DATA,
|
|
696
|
+
resolveScannerData,
|
|
697
|
+
generateSecurityPlan,
|
|
698
|
+
buildPlanFromAnalysis
|
|
699
|
+
};
|
|
700
|
+
//# sourceMappingURL=chunk-2UR7YN6T.js.map
|