@cognium/mcp-server 0.1.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.
- package/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/cache.d.ts +46 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +106 -0
- package/dist/cache.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/catalogs.d.ts +63 -0
- package/dist/resources/catalogs.d.ts.map +1 -0
- package/dist/resources/catalogs.js +92 -0
- package/dist/resources/catalogs.js.map +1 -0
- package/dist/resources/index.d.ts +13 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +94 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/schema.d.ts +81 -0
- package/dist/resources/schema.d.ts.map +1 -0
- package/dist/resources/schema.js +63 -0
- package/dist/resources/schema.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +41 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/attack-surface-summary.d.ts +24 -0
- package/dist/tools/attack-surface-summary.d.ts.map +1 -0
- package/dist/tools/attack-surface-summary.js +116 -0
- package/dist/tools/attack-surface-summary.js.map +1 -0
- package/dist/tools/check-sanitizer.d.ts +29 -0
- package/dist/tools/check-sanitizer.d.ts.map +1 -0
- package/dist/tools/check-sanitizer.js +82 -0
- package/dist/tools/check-sanitizer.js.map +1 -0
- package/dist/tools/describe-sink.d.ts +22 -0
- package/dist/tools/describe-sink.d.ts.map +1 -0
- package/dist/tools/describe-sink.js +47 -0
- package/dist/tools/describe-sink.js.map +1 -0
- package/dist/tools/describe-source.d.ts +27 -0
- package/dist/tools/describe-source.d.ts.map +1 -0
- package/dist/tools/describe-source.js +64 -0
- package/dist/tools/describe-source.js.map +1 -0
- package/dist/tools/explain-finding.d.ts +23 -0
- package/dist/tools/explain-finding.d.ts.map +1 -0
- package/dist/tools/explain-finding.js +65 -0
- package/dist/tools/explain-finding.js.map +1 -0
- package/dist/tools/find-similar.d.ts +34 -0
- package/dist/tools/find-similar.d.ts.map +1 -0
- package/dist/tools/find-similar.js +107 -0
- package/dist/tools/find-similar.js.map +1 -0
- package/dist/tools/list-entry-points.d.ts +22 -0
- package/dist/tools/list-entry-points.d.ts.map +1 -0
- package/dist/tools/list-entry-points.js +71 -0
- package/dist/tools/list-entry-points.js.map +1 -0
- package/dist/tools/list-reachable-sinks.d.ts +33 -0
- package/dist/tools/list-reachable-sinks.d.ts.map +1 -0
- package/dist/tools/list-reachable-sinks.js +116 -0
- package/dist/tools/list-reachable-sinks.js.map +1 -0
- package/dist/tools/refresh.d.ts +21 -0
- package/dist/tools/refresh.d.ts.map +1 -0
- package/dist/tools/refresh.js +39 -0
- package/dist/tools/refresh.js.map +1 -0
- package/dist/tools/scan.d.ts +42 -0
- package/dist/tools/scan.d.ts.map +1 -0
- package/dist/tools/scan.js +197 -0
- package/dist/tools/scan.js.map +1 -0
- package/dist/tools/taint-paths.d.ts +31 -0
- package/dist/tools/taint-paths.d.ts.map +1 -0
- package/dist/tools/taint-paths.js +55 -0
- package/dist/tools/taint-paths.js.map +1 -0
- package/dist/tools/types.d.ts +22 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +17 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/util/files.d.ts +33 -0
- package/dist/util/files.d.ts.map +1 -0
- package/dist/util/files.js +184 -0
- package/dist/util/files.js.map +1 -0
- package/dist/util/serialize.d.ts +29 -0
- package/dist/util/serialize.d.ts.map +1 -0
- package/dist/util/serialize.js +42 -0
- package/dist/util/serialize.js.map +1 -0
- package/dist/util/wasm.d.ts +9 -0
- package/dist/util/wasm.d.ts.map +1 -0
- package/dist/util/wasm.js +37 -0
- package/dist/util/wasm.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `refresh` tool — manual cache invalidation. The server auto-invalidates
|
|
3
|
+
* on file mtime change, but callers may want to force a re-scan (e.g.
|
|
4
|
+
* after a git checkout or when developing analyzer rules).
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import { textResult } from './types.js';
|
|
9
|
+
export const refreshInputShape = {
|
|
10
|
+
project_root: z.string().optional()
|
|
11
|
+
.describe('Absolute path to the project root to invalidate. If omitted, every cached project is cleared.'),
|
|
12
|
+
};
|
|
13
|
+
export const refreshConfig = {
|
|
14
|
+
title: 'Refresh analysis cache',
|
|
15
|
+
description: 'Invalidate cached analysis for one project (when `project_root` is provided) or every cached project ' +
|
|
16
|
+
'(when omitted). The next tool call that needs analysis will re-run `analyzeProject`. Use after a git ' +
|
|
17
|
+
'checkout, dependency change, or when authoring / testing analyzer rules.',
|
|
18
|
+
inputSchema: refreshInputShape,
|
|
19
|
+
};
|
|
20
|
+
export function makeRefreshHandler(ctx) {
|
|
21
|
+
return async (args) => {
|
|
22
|
+
if (args.project_root) {
|
|
23
|
+
const abs = resolve(args.project_root);
|
|
24
|
+
const removed = ctx.cache.invalidate(abs);
|
|
25
|
+
return textResult({
|
|
26
|
+
projectRoot: abs,
|
|
27
|
+
entriesRemoved: removed,
|
|
28
|
+
cacheSizeAfter: ctx.cache.size(),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const removed = ctx.cache.clear();
|
|
32
|
+
return textResult({
|
|
33
|
+
cleared: 'all',
|
|
34
|
+
entriesRemoved: removed,
|
|
35
|
+
cacheSizeAfter: ctx.cache.size(),
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/tools/refresh.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAChC,QAAQ,CAAC,+FAA+F,CAAC;CACpG,CAAC;AAEX,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EACT,uGAAuG;QACvG,uGAAuG;QACvG,0EAA0E;IAC5E,WAAW,EAAE,iBAAiB;CACtB,CAAC;AAEX,MAAM,UAAU,kBAAkB,CAAC,GAAgB;IACjD,OAAO,KAAK,EAAE,IAA+B,EAAuB,EAAE;QACpE,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC1C,OAAO,UAAU,CAAC;gBAChB,WAAW,EAAE,GAAG;gBAChB,cAAc,EAAE,OAAO;gBACvB,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;aACjC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAClC,OAAO,UAAU,CAAC;YAChB,OAAO,EAAE,KAAK;YACd,cAAc,EAAE,OAAO;YACvB,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;SACjC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `scan` tool — run circle-ir on a file or directory.
|
|
3
|
+
*
|
|
4
|
+
* The workhorse tool. Every other tool that needs analysis data pulls
|
|
5
|
+
* from the same `ProjectCache`, so calling `scan` first is the fastest
|
|
6
|
+
* path for a session (subsequent tool calls are cache hits).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import type { SupportedLanguage } from 'circle-ir';
|
|
10
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
11
|
+
export declare const scanInputShape: {
|
|
12
|
+
readonly path: z.ZodString;
|
|
13
|
+
readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
|
|
14
|
+
readonly severity: z.ZodOptional<z.ZodArray<z.ZodEnum<["critical", "high", "medium", "low"]>, "many">>;
|
|
15
|
+
readonly categories: z.ZodOptional<z.ZodArray<z.ZodEnum<["security", "reliability", "performance", "maintainability", "architecture"]>, "many">>;
|
|
16
|
+
readonly disabledPasses: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
17
|
+
readonly forceRefresh: z.ZodOptional<z.ZodBoolean>;
|
|
18
|
+
readonly crossFileBudgetMs: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
};
|
|
20
|
+
export declare const scanConfig: {
|
|
21
|
+
readonly title: "Scan project";
|
|
22
|
+
readonly description: string;
|
|
23
|
+
readonly inputSchema: {
|
|
24
|
+
readonly path: z.ZodString;
|
|
25
|
+
readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
|
|
26
|
+
readonly severity: z.ZodOptional<z.ZodArray<z.ZodEnum<["critical", "high", "medium", "low"]>, "many">>;
|
|
27
|
+
readonly categories: z.ZodOptional<z.ZodArray<z.ZodEnum<["security", "reliability", "performance", "maintainability", "architecture"]>, "many">>;
|
|
28
|
+
readonly disabledPasses: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
29
|
+
readonly forceRefresh: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
readonly crossFileBudgetMs: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export declare function makeScanHandler(ctx: ToolContext): (args: {
|
|
34
|
+
path: string;
|
|
35
|
+
language?: SupportedLanguage;
|
|
36
|
+
severity?: Array<"critical" | "high" | "medium" | "low">;
|
|
37
|
+
categories?: Array<"security" | "reliability" | "performance" | "maintainability" | "architecture">;
|
|
38
|
+
disabledPasses?: string[];
|
|
39
|
+
forceRefresh?: boolean;
|
|
40
|
+
crossFileBudgetMs?: number;
|
|
41
|
+
}) => Promise<ToolResult>;
|
|
42
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/tools/scan.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACc,iBAAiB,EAC1C,MAAM,WAAW,CAAC;AAkBnB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM1D,eAAO,MAAM,cAAc;;;;;;;;CAoBjB,CAAC;AAEX,eAAO,MAAM,UAAU;;;;;;;;;;;;CAQb,CAAC;AAgEX,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,IAChC,MAAM;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC,CAAC;IACzD,UAAU,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,aAAa,GAAG,aAAa,GAAG,iBAAiB,GAAG,cAAc,CAAC,CAAC;IACpG,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,KAAG,OAAO,CAAC,UAAU,CAAC,CA0FxB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `scan` tool — run circle-ir on a file or directory.
|
|
3
|
+
*
|
|
4
|
+
* The workhorse tool. Every other tool that needs analysis data pulls
|
|
5
|
+
* from the same `ProjectCache`, so calling `scan` first is the fastest
|
|
6
|
+
* path for a session (subsequent tool calls are cache hits).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { RULE_DEFINITIONS } from 'circle-ir';
|
|
10
|
+
import { resolve } from 'path';
|
|
11
|
+
import { existsSync, statSync } from 'fs';
|
|
12
|
+
import { textResult, errorResult } from './types.js';
|
|
13
|
+
import { truncateArray, truncateString, MAX_FINDINGS, MAX_TAINT_PATHS, MAX_STRING_LEN, } from '../util/serialize.js';
|
|
14
|
+
export const scanInputShape = {
|
|
15
|
+
path: z.string().describe('Absolute path to a file or directory to scan.'),
|
|
16
|
+
language: z.enum(['java', 'javascript', 'typescript', 'python', 'go', 'rust', 'bash', 'html'])
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Restrict analysis to a single language.'),
|
|
19
|
+
severity: z.array(z.enum(['critical', 'high', 'medium', 'low']))
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Filter findings to these severity levels.'),
|
|
22
|
+
categories: z.array(z.enum(['security', 'reliability', 'performance', 'maintainability', 'architecture']))
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Filter findings to these ISO-25010 categories.'),
|
|
25
|
+
disabledPasses: z.array(z.string())
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('circle-ir rule_ids to disable, e.g. ["naming-convention", "todo-in-prod"].'),
|
|
28
|
+
forceRefresh: z.boolean()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Skip the cache and re-analyze from disk.'),
|
|
31
|
+
crossFileBudgetMs: z.number().int().min(0)
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('Wall-time cap for the cross-file phase in ms. 0 = unlimited.'),
|
|
34
|
+
};
|
|
35
|
+
export const scanConfig = {
|
|
36
|
+
title: 'Scan project',
|
|
37
|
+
description: 'Run circle-ir static analysis (polyglot SAST pipeline) on a file or directory. ' +
|
|
38
|
+
'Returns SastFindings covering security, reliability, performance, maintainability, and architecture, ' +
|
|
39
|
+
'plus per-file taint flows and (for directory scans) cross-file taint paths. Results are cached per ' +
|
|
40
|
+
'project + option-set and invalidated by file mtime, so subsequent tool calls are effectively free.',
|
|
41
|
+
inputSchema: scanInputShape,
|
|
42
|
+
};
|
|
43
|
+
function compactFinding(f) {
|
|
44
|
+
return {
|
|
45
|
+
id: f.id,
|
|
46
|
+
rule_id: f.rule_id,
|
|
47
|
+
category: f.category,
|
|
48
|
+
severity: f.severity,
|
|
49
|
+
level: f.level,
|
|
50
|
+
cwe: f.cwe,
|
|
51
|
+
message: truncateString(f.message),
|
|
52
|
+
file: f.file,
|
|
53
|
+
line: f.line,
|
|
54
|
+
end_line: f.end_line,
|
|
55
|
+
column: f.column,
|
|
56
|
+
snippet: truncateString(f.snippet),
|
|
57
|
+
fix: truncateString(f.fix),
|
|
58
|
+
confidence: f.confidence,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function compactFlow(file, flow) {
|
|
62
|
+
const rule = RULE_DEFINITIONS[flow.sink_type];
|
|
63
|
+
return {
|
|
64
|
+
file,
|
|
65
|
+
source_type: flow.source_type,
|
|
66
|
+
source_line: flow.source_line,
|
|
67
|
+
sink_type: flow.sink_type,
|
|
68
|
+
sink_line: flow.sink_line,
|
|
69
|
+
cwe: rule?.cwe,
|
|
70
|
+
severity: rule?.severityLevel ?? 'high',
|
|
71
|
+
confidence: flow.confidence,
|
|
72
|
+
sanitized: flow.sanitized,
|
|
73
|
+
tags: flow.tags,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function compactTaintPath(p) {
|
|
77
|
+
return {
|
|
78
|
+
id: p.id,
|
|
79
|
+
source: {
|
|
80
|
+
file: p.source.file,
|
|
81
|
+
line: p.source.line,
|
|
82
|
+
type: p.source.type,
|
|
83
|
+
code: truncateString(p.source.code, 512),
|
|
84
|
+
},
|
|
85
|
+
sink: {
|
|
86
|
+
file: p.sink.file,
|
|
87
|
+
line: p.sink.line,
|
|
88
|
+
type: p.sink.type,
|
|
89
|
+
cwe: p.sink.cwe,
|
|
90
|
+
code: truncateString(p.sink.code, 512),
|
|
91
|
+
},
|
|
92
|
+
hops: p.hops.map(h => ({
|
|
93
|
+
file: h.file,
|
|
94
|
+
line: h.line,
|
|
95
|
+
variable: h.variable,
|
|
96
|
+
code: truncateString(h.code, 256),
|
|
97
|
+
})),
|
|
98
|
+
sanitizers_in_path: p.sanitizers_in_path,
|
|
99
|
+
confidence: p.confidence,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function makeScanHandler(ctx) {
|
|
103
|
+
return async (args) => {
|
|
104
|
+
const absPath = resolve(args.path);
|
|
105
|
+
if (!existsSync(absPath)) {
|
|
106
|
+
return errorResult(`Path not found: ${absPath}`);
|
|
107
|
+
}
|
|
108
|
+
const isDir = statSync(absPath).isDirectory();
|
|
109
|
+
const projectRoot = isDir ? absPath : resolve(absPath, '..');
|
|
110
|
+
if (args.forceRefresh) {
|
|
111
|
+
ctx.cache.invalidate(projectRoot);
|
|
112
|
+
}
|
|
113
|
+
const scanOpts = {
|
|
114
|
+
...(args.language ? { language: args.language } : {}),
|
|
115
|
+
...(args.disabledPasses ? { disabledPasses: args.disabledPasses } : {}),
|
|
116
|
+
...(args.crossFileBudgetMs !== undefined ? { crossFileBudgetMs: args.crossFileBudgetMs } : {}),
|
|
117
|
+
};
|
|
118
|
+
const { analysis, cacheHit, analysisMs, fileCount } = await ctx.cache.getOrCompute(projectRoot, scanOpts);
|
|
119
|
+
const findings = [];
|
|
120
|
+
const flows = [];
|
|
121
|
+
for (const fa of analysis.files) {
|
|
122
|
+
if (!isDir && fa.file !== absPath)
|
|
123
|
+
continue;
|
|
124
|
+
for (const f of fa.analysis.findings ?? [])
|
|
125
|
+
findings.push(f);
|
|
126
|
+
for (const fl of fa.analysis.taint.flows ?? [])
|
|
127
|
+
flows.push({ file: fa.file, flow: fl });
|
|
128
|
+
}
|
|
129
|
+
// Filter findings.
|
|
130
|
+
let filteredFindings = findings;
|
|
131
|
+
if (args.severity && args.severity.length > 0) {
|
|
132
|
+
const set = new Set(args.severity);
|
|
133
|
+
filteredFindings = filteredFindings.filter(f => set.has(f.severity));
|
|
134
|
+
}
|
|
135
|
+
if (args.categories && args.categories.length > 0) {
|
|
136
|
+
const set = new Set(args.categories);
|
|
137
|
+
filteredFindings = filteredFindings.filter(f => set.has(f.category));
|
|
138
|
+
}
|
|
139
|
+
// Filter flows: flows are always 'security'; drop if categories filter excludes 'security'.
|
|
140
|
+
let filteredFlows = flows;
|
|
141
|
+
if (args.categories && !args.categories.includes('security')) {
|
|
142
|
+
filteredFlows = [];
|
|
143
|
+
}
|
|
144
|
+
if (args.severity && args.severity.length > 0) {
|
|
145
|
+
const set = new Set(args.severity);
|
|
146
|
+
filteredFlows = filteredFlows.filter(({ flow }) => {
|
|
147
|
+
const sev = RULE_DEFINITIONS[flow.sink_type]?.severityLevel ?? 'high';
|
|
148
|
+
return set.has(sev);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const taintPaths = isDir ? analysis.taint_paths : [];
|
|
152
|
+
const { items: findingsSlice, truncated: fTrunc, totalCount: fTotal } = truncateArray(filteredFindings.map(compactFinding), MAX_FINDINGS);
|
|
153
|
+
const { items: flowsSlice, truncated: flTrunc, totalCount: flTotal } = truncateArray(filteredFlows.map(({ file, flow }) => compactFlow(file, flow)), MAX_FINDINGS);
|
|
154
|
+
const { items: pathsSlice, truncated: pTrunc, totalCount: pTotal } = truncateArray(taintPaths.map(compactTaintPath), MAX_TAINT_PATHS);
|
|
155
|
+
const summary = {
|
|
156
|
+
totalFindings: fTotal,
|
|
157
|
+
totalTaintFlows: flTotal,
|
|
158
|
+
totalCrossFileTaintPaths: pTotal,
|
|
159
|
+
byCategory: countBy(filteredFindings, f => f.category),
|
|
160
|
+
bySeverity: countBy(filteredFindings, f => f.severity),
|
|
161
|
+
byRuleId: topN(countBy(filteredFindings, f => f.rule_id), 10),
|
|
162
|
+
byTaintSinkType: countBy(filteredFlows.map(x => x.flow), f => f.sink_type),
|
|
163
|
+
};
|
|
164
|
+
return textResult({
|
|
165
|
+
projectRoot,
|
|
166
|
+
scannedPath: absPath,
|
|
167
|
+
fileCount,
|
|
168
|
+
cacheHit,
|
|
169
|
+
analysisMs,
|
|
170
|
+
crossFileBudgetExceeded: analysis.cross_file_budget_exceeded === true,
|
|
171
|
+
summary,
|
|
172
|
+
findings: findingsSlice,
|
|
173
|
+
findingsTruncated: fTrunc,
|
|
174
|
+
taintFlows: flowsSlice,
|
|
175
|
+
taintFlowsTruncated: flTrunc,
|
|
176
|
+
crossFileTaintPaths: pathsSlice,
|
|
177
|
+
crossFileTaintPathsTruncated: pTrunc,
|
|
178
|
+
note: (fTrunc || flTrunc || pTrunc)
|
|
179
|
+
? `Response truncated (${MAX_FINDINGS} findings / ${MAX_FINDINGS} flows / ${MAX_TAINT_PATHS} paths max). Narrow via 'severity' / 'categories' or query 'find_similar' / 'list_reachable_sinks'.`
|
|
180
|
+
: undefined,
|
|
181
|
+
_limits: { maxStringLen: MAX_STRING_LEN, maxFindings: MAX_FINDINGS, maxTaintPaths: MAX_TAINT_PATHS },
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function countBy(items, key) {
|
|
186
|
+
const out = {};
|
|
187
|
+
for (const i of items) {
|
|
188
|
+
const k = key(i);
|
|
189
|
+
out[k] = (out[k] ?? 0) + 1;
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
function topN(map, n) {
|
|
194
|
+
const entries = Object.entries(map).sort((a, b) => b[1] - a[1]).slice(0, n);
|
|
195
|
+
return Object.fromEntries(entries);
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/tools/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `taint_paths` tool — list cross-file taint flows with optional filters.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
6
|
+
export declare const taintPathsInputShape: {
|
|
7
|
+
readonly project_root: z.ZodString;
|
|
8
|
+
readonly source_file: z.ZodOptional<z.ZodString>;
|
|
9
|
+
readonly sink_file: z.ZodOptional<z.ZodString>;
|
|
10
|
+
readonly sink_type: z.ZodOptional<z.ZodString>;
|
|
11
|
+
readonly max_paths: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
};
|
|
13
|
+
export declare const taintPathsConfig: {
|
|
14
|
+
readonly title: "List cross-file taint paths";
|
|
15
|
+
readonly description: string;
|
|
16
|
+
readonly inputSchema: {
|
|
17
|
+
readonly project_root: z.ZodString;
|
|
18
|
+
readonly source_file: z.ZodOptional<z.ZodString>;
|
|
19
|
+
readonly sink_file: z.ZodOptional<z.ZodString>;
|
|
20
|
+
readonly sink_type: z.ZodOptional<z.ZodString>;
|
|
21
|
+
readonly max_paths: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export declare function makeTaintPathsHandler(ctx: ToolContext): (args: {
|
|
25
|
+
project_root: string;
|
|
26
|
+
source_file?: string;
|
|
27
|
+
sink_file?: string;
|
|
28
|
+
sink_type?: string;
|
|
29
|
+
max_paths?: number;
|
|
30
|
+
}) => Promise<ToolResult>;
|
|
31
|
+
//# sourceMappingURL=taint-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taint-paths.d.ts","sourceRoot":"","sources":["../../src/tools/taint-paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,oBAAoB;;;;;;CAQvB,CAAC;AAEX,eAAO,MAAM,gBAAgB;;;;;;;;;;CAOnB,CAAC;AAEX,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,IACtC,MAAM;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,KAAG,OAAO,CAAC,UAAU,CAAC,CA6BxB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `taint_paths` tool — list cross-file taint flows with optional filters.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import { textResult } from './types.js';
|
|
7
|
+
import { truncateArray, truncateString, MAX_TAINT_PATHS } from '../util/serialize.js';
|
|
8
|
+
export const taintPathsInputShape = {
|
|
9
|
+
project_root: z.string().describe('Absolute path to the project root.'),
|
|
10
|
+
source_file: z.string().optional().describe('Only paths whose source is in this file.'),
|
|
11
|
+
sink_file: z.string().optional().describe('Only paths whose sink is in this file.'),
|
|
12
|
+
sink_type: z.string().optional()
|
|
13
|
+
.describe('Only paths with this sink type (e.g. "sql_injection", "command_injection").'),
|
|
14
|
+
max_paths: z.number().int().min(1).max(500).optional()
|
|
15
|
+
.describe('Cap on returned paths. Defaults to 50.'),
|
|
16
|
+
};
|
|
17
|
+
export const taintPathsConfig = {
|
|
18
|
+
title: 'List cross-file taint paths',
|
|
19
|
+
description: 'List cross-file taint flows in a previously-scanned project, filtered by source file, sink file, or ' +
|
|
20
|
+
'sink type. Use to enumerate every attacker-reachable data flow between files. Requires that `scan` ' +
|
|
21
|
+
'has been called on the project root.',
|
|
22
|
+
inputSchema: taintPathsInputShape,
|
|
23
|
+
};
|
|
24
|
+
export function makeTaintPathsHandler(ctx) {
|
|
25
|
+
return async (args) => {
|
|
26
|
+
const root = resolve(args.project_root);
|
|
27
|
+
const { analysis, cacheHit, analysisMs } = await ctx.cache.getOrCompute(root, {});
|
|
28
|
+
const cap = args.max_paths ?? 50;
|
|
29
|
+
let paths = analysis.taint_paths;
|
|
30
|
+
if (args.source_file)
|
|
31
|
+
paths = paths.filter(p => p.source.file === args.source_file || p.source.file.endsWith(args.source_file));
|
|
32
|
+
if (args.sink_file)
|
|
33
|
+
paths = paths.filter(p => p.sink.file === args.sink_file || p.sink.file.endsWith(args.sink_file));
|
|
34
|
+
if (args.sink_type)
|
|
35
|
+
paths = paths.filter(p => p.sink.type === args.sink_type);
|
|
36
|
+
const { items, truncated, totalCount } = truncateArray(paths, Math.min(cap, MAX_TAINT_PATHS));
|
|
37
|
+
return textResult({
|
|
38
|
+
projectRoot: root,
|
|
39
|
+
cacheHit,
|
|
40
|
+
analysisMs,
|
|
41
|
+
crossFileBudgetExceeded: analysis.cross_file_budget_exceeded === true,
|
|
42
|
+
totalMatching: totalCount,
|
|
43
|
+
truncated,
|
|
44
|
+
paths: items.map(p => ({
|
|
45
|
+
id: p.id,
|
|
46
|
+
source: { ...p.source, code: truncateString(p.source.code, 512) },
|
|
47
|
+
sink: { ...p.sink, code: truncateString(p.sink.code, 512) },
|
|
48
|
+
hops: p.hops.map(h => ({ ...h, code: truncateString(h.code, 256) })),
|
|
49
|
+
sanitizers_in_path: p.sanitizers_in_path,
|
|
50
|
+
confidence: p.confidence,
|
|
51
|
+
})),
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=taint-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taint-paths.js","sourceRoot":"","sources":["../../src/tools/taint-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for tool handlers.
|
|
3
|
+
*/
|
|
4
|
+
import type { ProjectCache } from '../cache.js';
|
|
5
|
+
export interface ToolContext {
|
|
6
|
+
cache: ProjectCache;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* MCP `CallToolResult`-compatible shape. We construct the JSON payload
|
|
10
|
+
* ourselves so tools have full control over serialization + truncation.
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolResult {
|
|
13
|
+
content: Array<{
|
|
14
|
+
type: 'text';
|
|
15
|
+
text: string;
|
|
16
|
+
}>;
|
|
17
|
+
structuredContent?: Record<string, unknown>;
|
|
18
|
+
isError?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function textResult(payload: unknown, structured?: Record<string, unknown>): ToolResult;
|
|
21
|
+
export declare function errorResult(message: string): ToolResult;
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAK7F;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAKvD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for tool handlers.
|
|
3
|
+
*/
|
|
4
|
+
export function textResult(payload, structured) {
|
|
5
|
+
const text = typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2);
|
|
6
|
+
const result = { content: [{ type: 'text', text }] };
|
|
7
|
+
if (structured)
|
|
8
|
+
result.structuredContent = structured;
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
export function errorResult(message) {
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
14
|
+
isError: true,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,UAAoC;IAC/E,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtF,MAAM,MAAM,GAAe,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACjE,IAAI,UAAU;QAAE,MAAM,CAAC,iBAAiB,GAAG,UAAU,CAAC;IACtD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;QACtD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File collection + language detection utilities.
|
|
3
|
+
*
|
|
4
|
+
* A small standalone reimplementation so the MCP server does not depend on
|
|
5
|
+
* the CLI package. Mirrors the extension → language mapping from
|
|
6
|
+
* `packages/cli/src/cli.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import type { SupportedLanguage } from 'circle-ir';
|
|
9
|
+
export declare function detectLanguage(filePath: string): SupportedLanguage | null;
|
|
10
|
+
export interface CollectedFile {
|
|
11
|
+
filePath: string;
|
|
12
|
+
language: SupportedLanguage;
|
|
13
|
+
code: string;
|
|
14
|
+
mtimeMs: number;
|
|
15
|
+
}
|
|
16
|
+
export interface CollectOptions {
|
|
17
|
+
/** Restrict to a single language, e.g. 'java'. */
|
|
18
|
+
language?: SupportedLanguage;
|
|
19
|
+
/** Absolute max number of files to collect (safety cap). */
|
|
20
|
+
maxFiles?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Recursively collect source files under `root`. Skips hidden dirs,
|
|
24
|
+
* `node_modules`, build outputs, and language-mismatched files.
|
|
25
|
+
*/
|
|
26
|
+
export declare function collectFiles(root: string, opts?: CollectOptions): CollectedFile[];
|
|
27
|
+
/**
|
|
28
|
+
* Cheap mtime index used for cache invalidation. Same walking logic as
|
|
29
|
+
* `collectFiles` but skips reading file contents.
|
|
30
|
+
*/
|
|
31
|
+
export declare function indexMtimes(root: string, opts?: CollectOptions): Map<string, number>;
|
|
32
|
+
export declare function mtimesEqual(a: Map<string, number>, b: Map<string, number>): boolean;
|
|
33
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/util/files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAoCnD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAGzE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,aAAa,EAAE,CA2DrF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8CxF;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAMnF"}
|