guardlink 1.0.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 +30 -0
- package/LICENSE +21 -0
- package/README.md +344 -0
- package/dist/agents/config.d.ts +46 -0
- package/dist/agents/config.d.ts.map +1 -0
- package/dist/agents/config.js +189 -0
- package/dist/agents/config.js.map +1 -0
- package/dist/agents/index.d.ts +24 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +42 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/launcher.d.ts +54 -0
- package/dist/agents/launcher.d.ts.map +1 -0
- package/dist/agents/launcher.js +152 -0
- package/dist/agents/launcher.js.map +1 -0
- package/dist/agents/prompts.d.ts +14 -0
- package/dist/agents/prompts.d.ts.map +1 -0
- package/dist/agents/prompts.js +120 -0
- package/dist/agents/prompts.js.map +1 -0
- package/dist/analyze/index.d.ts +80 -0
- package/dist/analyze/index.d.ts.map +1 -0
- package/dist/analyze/index.js +306 -0
- package/dist/analyze/index.js.map +1 -0
- package/dist/analyze/llm.d.ts +52 -0
- package/dist/analyze/llm.d.ts.map +1 -0
- package/dist/analyze/llm.js +295 -0
- package/dist/analyze/llm.js.map +1 -0
- package/dist/analyze/prompts.d.ts +14 -0
- package/dist/analyze/prompts.d.ts.map +1 -0
- package/dist/analyze/prompts.js +205 -0
- package/dist/analyze/prompts.js.map +1 -0
- package/dist/analyzer/index.d.ts +5 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +5 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/analyzer/sarif.d.ts +84 -0
- package/dist/analyzer/sarif.d.ts.map +1 -0
- package/dist/analyzer/sarif.js +149 -0
- package/dist/analyzer/sarif.js.map +1 -0
- package/dist/cli/index.d.ts +25 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +821 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/dashboard/data.d.ts +52 -0
- package/dist/dashboard/data.d.ts.map +1 -0
- package/dist/dashboard/data.js +93 -0
- package/dist/dashboard/data.js.map +1 -0
- package/dist/dashboard/diagrams.d.ts +25 -0
- package/dist/dashboard/diagrams.d.ts.map +1 -0
- package/dist/dashboard/diagrams.js +243 -0
- package/dist/dashboard/diagrams.js.map +1 -0
- package/dist/dashboard/generate.d.ts +17 -0
- package/dist/dashboard/generate.d.ts.map +1 -0
- package/dist/dashboard/generate.js +1258 -0
- package/dist/dashboard/generate.js.map +1 -0
- package/dist/dashboard/index.d.ts +7 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +7 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/diff/engine.d.ts +51 -0
- package/dist/diff/engine.d.ts.map +1 -0
- package/dist/diff/engine.js +153 -0
- package/dist/diff/engine.js.map +1 -0
- package/dist/diff/format.d.ts +10 -0
- package/dist/diff/format.d.ts.map +1 -0
- package/dist/diff/format.js +111 -0
- package/dist/diff/format.js.map +1 -0
- package/dist/diff/git.d.ts +24 -0
- package/dist/diff/git.d.ts.map +1 -0
- package/dist/diff/git.js +85 -0
- package/dist/diff/git.js.map +1 -0
- package/dist/diff/index.d.ts +7 -0
- package/dist/diff/index.d.ts.map +1 -0
- package/dist/diff/index.js +7 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/init/detect.d.ts +42 -0
- package/dist/init/detect.d.ts.map +1 -0
- package/dist/init/detect.js +185 -0
- package/dist/init/detect.js.map +1 -0
- package/dist/init/index.d.ts +39 -0
- package/dist/init/index.d.ts.map +1 -0
- package/dist/init/index.js +228 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/picker.d.ts +32 -0
- package/dist/init/picker.d.ts.map +1 -0
- package/dist/init/picker.js +105 -0
- package/dist/init/picker.js.map +1 -0
- package/dist/init/templates.d.ts +25 -0
- package/dist/init/templates.d.ts.map +1 -0
- package/dist/init/templates.js +263 -0
- package/dist/init/templates.js.map +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +18 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/lookup.d.ts +27 -0
- package/dist/mcp/lookup.d.ts.map +1 -0
- package/dist/mcp/lookup.js +282 -0
- package/dist/mcp/lookup.js.map +1 -0
- package/dist/mcp/server.d.ts +41 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +388 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/suggest.d.ts +35 -0
- package/dist/mcp/suggest.d.ts.map +1 -0
- package/dist/mcp/suggest.js +268 -0
- package/dist/mcp/suggest.js.map +1 -0
- package/dist/parser/comment-strip.d.ts +15 -0
- package/dist/parser/comment-strip.d.ts.map +1 -0
- package/dist/parser/comment-strip.js +76 -0
- package/dist/parser/comment-strip.js.map +1 -0
- package/dist/parser/index.d.ts +10 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +9 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/normalize.d.ts +22 -0
- package/dist/parser/normalize.d.ts.map +1 -0
- package/dist/parser/normalize.js +42 -0
- package/dist/parser/normalize.js.map +1 -0
- package/dist/parser/parse-file.d.ts +18 -0
- package/dist/parser/parse-file.d.ts.map +1 -0
- package/dist/parser/parse-file.js +68 -0
- package/dist/parser/parse-file.js.map +1 -0
- package/dist/parser/parse-line.d.ts +21 -0
- package/dist/parser/parse-line.d.ts.map +1 -0
- package/dist/parser/parse-line.js +230 -0
- package/dist/parser/parse-line.js.map +1 -0
- package/dist/parser/parse-project.d.ts +31 -0
- package/dist/parser/parse-project.d.ts.map +1 -0
- package/dist/parser/parse-project.js +281 -0
- package/dist/parser/parse-project.js.map +1 -0
- package/dist/report/index.d.ts +6 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +6 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/mermaid.d.ts +15 -0
- package/dist/report/mermaid.d.ts.map +1 -0
- package/dist/report/mermaid.js +260 -0
- package/dist/report/mermaid.js.map +1 -0
- package/dist/report/report.d.ts +16 -0
- package/dist/report/report.d.ts.map +1 -0
- package/dist/report/report.js +211 -0
- package/dist/report/report.js.map +1 -0
- package/dist/tui/commands.d.ts +42 -0
- package/dist/tui/commands.d.ts.map +1 -0
- package/dist/tui/commands.js +1216 -0
- package/dist/tui/commands.js.map +1 -0
- package/dist/tui/config.d.ts +27 -0
- package/dist/tui/config.d.ts.map +1 -0
- package/dist/tui/config.js +27 -0
- package/dist/tui/config.js.map +1 -0
- package/dist/tui/format.d.ts +63 -0
- package/dist/tui/format.d.ts.map +1 -0
- package/dist/tui/format.js +253 -0
- package/dist/tui/format.js.map +1 -0
- package/dist/tui/index.d.ts +18 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +470 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/input.d.ts +63 -0
- package/dist/tui/input.d.ts.map +1 -0
- package/dist/tui/input.js +454 -0
- package/dist/tui/input.js.map +1 -0
- package/dist/types/index.d.ts +254 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink MCP Server — Model Context Protocol integration (§8.2).
|
|
3
|
+
*
|
|
4
|
+
* Tools:
|
|
5
|
+
* guardlink_parse — Parse annotations, return threat model
|
|
6
|
+
* guardlink_status — Coverage stats and unmitigated exposures
|
|
7
|
+
* guardlink_validate — Syntax errors and dangling references
|
|
8
|
+
* guardlink_suggest — Given a code diff or file, suggest annotations
|
|
9
|
+
* guardlink_lookup — Query the threat model graph
|
|
10
|
+
* guardlink_threat_report — AI threat report generation (STRIDE, DREAD, etc.)
|
|
11
|
+
* guardlink_annotate — Build annotation prompt for the calling agent
|
|
12
|
+
* guardlink_report — Generate markdown report + JSON
|
|
13
|
+
* guardlink_dashboard — Generate HTML threat model dashboard
|
|
14
|
+
* guardlink_sarif — Export SARIF 2.1.0
|
|
15
|
+
* guardlink_diff — Compare threat model against a git ref
|
|
16
|
+
* guardlink_threat_reports — List saved AI threat report files
|
|
17
|
+
*
|
|
18
|
+
* Resources:
|
|
19
|
+
* guardlink://model — Full ThreatModel JSON
|
|
20
|
+
* guardlink://definitions — Assets, threats, controls
|
|
21
|
+
* guardlink://unmitigated — Unmitigated exposures list
|
|
22
|
+
*
|
|
23
|
+
* Transport: stdio (for Claude Code .mcp.json, Cursor, etc.)
|
|
24
|
+
*
|
|
25
|
+
* @exposes #mcp to #path-traversal [high] cwe:CWE-22 -- "All tools accept root param from external AI agents"
|
|
26
|
+
* @exposes #mcp to #prompt-injection [medium] cwe:CWE-77 -- "guardlink_suggest output fed back to calling LLM"
|
|
27
|
+
* @exposes #mcp to #arbitrary-write [high] cwe:CWE-73 -- "guardlink_report and guardlink_dashboard write files"
|
|
28
|
+
* @exposes #mcp to #data-exposure [medium] cwe:CWE-200 -- "Exposes threat model details to connected agents"
|
|
29
|
+
* @accepts #path-traversal on #mcp -- "MCP clients (Claude Code, Cursor) are trusted local agents"
|
|
30
|
+
* @accepts #arbitrary-write on #mcp -- "MCP clients are trusted local agents with filesystem access"
|
|
31
|
+
* @accepts #prompt-injection on #mcp -- "Suggest output is intended for LLM consumption"
|
|
32
|
+
* @accepts #data-exposure on #mcp -- "Exposing threat model to agents is the core MCP feature"
|
|
33
|
+
* @boundary between #mcp and External_AI_Agents (#mcp-boundary) -- "Primary trust boundary: external AI agents invoke tools over stdio"
|
|
34
|
+
* @flows External_AI_Agents -> #mcp via stdio -- "Tool calls received from AI agent over stdio transport"
|
|
35
|
+
* @flows #mcp -> #parser via getModel -- "MCP tools invoke parser to build threat model"
|
|
36
|
+
* @flows #mcp -> External_AI_Agents via response -- "Tool results returned to calling agent"
|
|
37
|
+
* @handles internal on #mcp -- "Processes and exposes security-sensitive threat model data"
|
|
38
|
+
*/
|
|
39
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
40
|
+
import { z } from 'zod';
|
|
41
|
+
import { parseProject } from '../parser/index.js';
|
|
42
|
+
import { generateSarif } from '../analyzer/index.js';
|
|
43
|
+
import { generateReport } from '../report/index.js';
|
|
44
|
+
import { generateDashboardHTML } from '../dashboard/index.js';
|
|
45
|
+
import { diffModels, parseAtRef } from '../diff/index.js';
|
|
46
|
+
import { lookup } from './lookup.js';
|
|
47
|
+
import { suggestAnnotations } from './suggest.js';
|
|
48
|
+
import { generateThreatReport, listThreatReports, loadThreatReportsForDashboard, buildConfig, serializeModelCompact, FRAMEWORK_LABELS, FRAMEWORK_PROMPTS, buildUserMessage } from '../analyze/index.js';
|
|
49
|
+
import { buildAnnotatePrompt } from '../agents/prompts.js';
|
|
50
|
+
// ─── Cached model ────────────────────────────────────────────────────
|
|
51
|
+
let cachedModel = null;
|
|
52
|
+
let cachedDiagnostics = [];
|
|
53
|
+
let cachedRoot = '';
|
|
54
|
+
async function getModel(root) {
|
|
55
|
+
if (cachedModel && cachedRoot === root) {
|
|
56
|
+
return { model: cachedModel, diagnostics: cachedDiagnostics };
|
|
57
|
+
}
|
|
58
|
+
const result = await parseProject({ root, project: 'unknown' });
|
|
59
|
+
cachedModel = result.model;
|
|
60
|
+
cachedDiagnostics = result.diagnostics;
|
|
61
|
+
cachedRoot = root;
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function invalidateCache() {
|
|
65
|
+
cachedModel = null;
|
|
66
|
+
cachedDiagnostics = [];
|
|
67
|
+
}
|
|
68
|
+
// ─── Server setup ────────────────────────────────────────────────────
|
|
69
|
+
export function createServer() {
|
|
70
|
+
const server = new McpServer({
|
|
71
|
+
name: 'guardlink',
|
|
72
|
+
version: '1.0.0',
|
|
73
|
+
});
|
|
74
|
+
// ── Tool: guardlink_parse ──
|
|
75
|
+
server.tool('guardlink_parse', 'Parse GuardLink annotations from the project and return the full threat model as JSON', { root: z.string().describe('Project root directory').default('.') }, async ({ root }) => {
|
|
76
|
+
invalidateCache();
|
|
77
|
+
const { model } = await getModel(root);
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: 'text', text: JSON.stringify(model, null, 2) }],
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
// ── Tool: guardlink_status ──
|
|
83
|
+
server.tool('guardlink_status', 'Return coverage statistics: asset/threat/control counts, unmitigated exposures, coverage percentage', { root: z.string().describe('Project root directory').default('.') }, async ({ root }) => {
|
|
84
|
+
const { model } = await getModel(root);
|
|
85
|
+
const mitigated = new Set();
|
|
86
|
+
const accepted = new Set();
|
|
87
|
+
for (const m of model.mitigations)
|
|
88
|
+
mitigated.add(`${m.asset}::${m.threat}`);
|
|
89
|
+
for (const a of model.acceptances)
|
|
90
|
+
accepted.add(`${a.asset}::${a.threat}`);
|
|
91
|
+
const unmitigated = model.exposures.filter(e => !mitigated.has(`${e.asset}::${e.threat}`) && !accepted.has(`${e.asset}::${e.threat}`));
|
|
92
|
+
const status = {
|
|
93
|
+
assets: model.assets.length,
|
|
94
|
+
threats: model.threats.length,
|
|
95
|
+
controls: model.controls.length,
|
|
96
|
+
mitigations: model.mitigations.length,
|
|
97
|
+
exposures: model.exposures.length,
|
|
98
|
+
acceptances: model.acceptances.length,
|
|
99
|
+
flows: model.flows.length,
|
|
100
|
+
boundaries: model.boundaries.length,
|
|
101
|
+
unmitigated: unmitigated.map(e => ({
|
|
102
|
+
asset: e.asset,
|
|
103
|
+
threat: e.threat,
|
|
104
|
+
severity: e.severity,
|
|
105
|
+
file: e.location.file,
|
|
106
|
+
line: e.location.line,
|
|
107
|
+
})),
|
|
108
|
+
coverage: model.coverage,
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: 'text', text: JSON.stringify(status, null, 2) }],
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
// ── Tool: guardlink_validate ──
|
|
115
|
+
server.tool('guardlink_validate', 'Check annotations for syntax errors, duplicate IDs, and dangling references. Returns structured error list.', { root: z.string().describe('Project root directory').default('.') }, async ({ root }) => {
|
|
116
|
+
invalidateCache();
|
|
117
|
+
const { model, diagnostics } = await getModel(root);
|
|
118
|
+
// Compute dangling refs
|
|
119
|
+
const definedIds = new Set();
|
|
120
|
+
for (const a of model.assets) {
|
|
121
|
+
if (a.id)
|
|
122
|
+
definedIds.add(a.id);
|
|
123
|
+
definedIds.add(a.path.join('.'));
|
|
124
|
+
}
|
|
125
|
+
for (const t of model.threats) {
|
|
126
|
+
if (t.id)
|
|
127
|
+
definedIds.add(t.id);
|
|
128
|
+
}
|
|
129
|
+
for (const c of model.controls) {
|
|
130
|
+
if (c.id)
|
|
131
|
+
definedIds.add(c.id);
|
|
132
|
+
}
|
|
133
|
+
const errors = diagnostics.filter(d => d.level === 'error');
|
|
134
|
+
const warnings = diagnostics.filter(d => d.level === 'warning');
|
|
135
|
+
const result = {
|
|
136
|
+
valid: errors.length === 0,
|
|
137
|
+
errors: errors.map(d => ({ file: d.file, line: d.line, message: d.message })),
|
|
138
|
+
warnings: warnings.map(d => ({ file: d.file, line: d.line, message: d.message })),
|
|
139
|
+
summary: `${errors.length} error(s), ${warnings.length} warning(s)`,
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
// ── Tool: guardlink_suggest ──
|
|
146
|
+
server.tool('guardlink_suggest', 'Given a file path or code diff, suggest appropriate GuardLink annotations based on code patterns, imports, and function signatures', {
|
|
147
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
148
|
+
file: z.string().describe('File path relative to root to analyze').optional(),
|
|
149
|
+
diff: z.string().describe('Git diff text to analyze for new code needing annotations').optional(),
|
|
150
|
+
}, async ({ root, file, diff }) => {
|
|
151
|
+
const { model } = await getModel(root);
|
|
152
|
+
const suggestions = await suggestAnnotations({ root, model, file, diff });
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: 'text', text: JSON.stringify(suggestions, null, 2) }],
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
// ── Tool: guardlink_lookup ──
|
|
158
|
+
server.tool('guardlink_lookup', 'Query the threat model graph. Find assets, threats, controls, flows, exposures by ID or relationship. Examples: "what threats target #auth?", "flows into Scanner", "unmitigated exposures"', {
|
|
159
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
160
|
+
query: z.string().describe('Natural language or structured query: asset ID, threat ID, "flows into X", "threats for X", "unmitigated", "controls for X"'),
|
|
161
|
+
}, async ({ root, query }) => {
|
|
162
|
+
const { model } = await getModel(root);
|
|
163
|
+
const result = lookup(model, query);
|
|
164
|
+
return {
|
|
165
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
// ── Tool: guardlink_threat_report ──
|
|
169
|
+
server.tool('guardlink_threat_report', 'Generate an AI threat report using a security framework (STRIDE, DREAD, PASTA, attacker, rapid, general). If an LLM API key is set in environment, runs analysis internally and saves result. If no API key is set, returns the framework prompt and serialized threat model for the calling agent to analyze directly — write the result as markdown to .guardlink/threat-reports/.', {
|
|
170
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
171
|
+
framework: z.enum(['stride', 'dread', 'pasta', 'attacker', 'rapid', 'general']).describe('Analysis framework').default('general'),
|
|
172
|
+
provider: z.string().describe('LLM provider: anthropic, openai, openrouter, deepseek (auto-detected from env)').optional(),
|
|
173
|
+
model: z.string().describe('Model name override').optional(),
|
|
174
|
+
custom_prompt: z.string().describe('Custom analysis prompt to replace the framework header').optional(),
|
|
175
|
+
}, async ({ root, framework, provider, model: modelName, custom_prompt }) => {
|
|
176
|
+
const { model: threatModel } = await getModel(root);
|
|
177
|
+
if (threatModel.annotations_parsed === 0) {
|
|
178
|
+
return {
|
|
179
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
180
|
+
error: 'No annotations found. Add GuardLink annotations to your code first.',
|
|
181
|
+
}) }],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const fw = framework;
|
|
185
|
+
const llmConfig = buildConfig({ provider, model: modelName });
|
|
186
|
+
// Agent mode: no API key — return prompt + compact model for the calling agent
|
|
187
|
+
if (!llmConfig) {
|
|
188
|
+
const serialized = serializeModelCompact(threatModel);
|
|
189
|
+
const systemPrompt = FRAMEWORK_PROMPTS[fw] || FRAMEWORK_PROMPTS.general;
|
|
190
|
+
const userMessage = buildUserMessage(serialized, fw, custom_prompt);
|
|
191
|
+
return {
|
|
192
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
193
|
+
mode: 'agent',
|
|
194
|
+
message: 'No LLM API key found. Returning the threat report prompt and threat model for you to generate directly. Write the report as markdown and save it to .guardlink/threat-reports/. Call guardlink_parse or read guardlink://model for full detail if needed.',
|
|
195
|
+
framework,
|
|
196
|
+
label: FRAMEWORK_LABELS[fw],
|
|
197
|
+
system_prompt: systemPrompt,
|
|
198
|
+
user_prompt: userMessage,
|
|
199
|
+
save_to: `.guardlink/threat-reports/${new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)}-${framework}.md`,
|
|
200
|
+
}, null, 2) }],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// API mode: call LLM internally
|
|
204
|
+
try {
|
|
205
|
+
const result = await generateThreatReport({
|
|
206
|
+
root,
|
|
207
|
+
model: threatModel,
|
|
208
|
+
framework: fw,
|
|
209
|
+
llmConfig,
|
|
210
|
+
customPrompt: custom_prompt,
|
|
211
|
+
stream: false,
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
215
|
+
mode: 'api',
|
|
216
|
+
framework: result.framework,
|
|
217
|
+
label: result.label,
|
|
218
|
+
model: result.model,
|
|
219
|
+
savedTo: result.savedTo,
|
|
220
|
+
inputTokens: result.inputTokens,
|
|
221
|
+
outputTokens: result.outputTokens,
|
|
222
|
+
content: result.content,
|
|
223
|
+
}, null, 2) }],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
// ── Tool: guardlink_annotate ──
|
|
233
|
+
server.tool('guardlink_annotate', 'Build an annotation prompt with project context, GuardLink reference docs, and GAL syntax guidelines. The calling agent should use this prompt to read source files and add security annotations directly. Returns the prompt text — the agent should then read files, decide annotation placement, and write comments.', {
|
|
234
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
235
|
+
prompt: z.string().describe('Annotation instructions (e.g., "annotate auth endpoints for OWASP Top 10")'),
|
|
236
|
+
}, async ({ root, prompt }) => {
|
|
237
|
+
let model = null;
|
|
238
|
+
try {
|
|
239
|
+
const result = await getModel(root);
|
|
240
|
+
if (result.model.annotations_parsed > 0) {
|
|
241
|
+
model = result.model;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch { /* no model yet — fine */ }
|
|
245
|
+
const annotatePrompt = buildAnnotatePrompt(prompt, root, model);
|
|
246
|
+
return {
|
|
247
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
248
|
+
mode: 'agent',
|
|
249
|
+
message: 'Annotation prompt built with project context. Read the source files in the project directory, then add GuardLink annotations as code comments following the guidelines in the prompt. After annotating, call guardlink_parse to verify the annotations were parsed correctly.',
|
|
250
|
+
prompt: annotatePrompt,
|
|
251
|
+
guidelines: [
|
|
252
|
+
'Add annotations as comments directly above security-relevant code',
|
|
253
|
+
'Use the project\'s comment style (// for TS/JS/Rust/Go, # for Python/Ruby/Shell)',
|
|
254
|
+
'After annotating, call guardlink_parse to verify results',
|
|
255
|
+
],
|
|
256
|
+
}, null, 2) }],
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
// ── Tool: guardlink_report ──
|
|
260
|
+
server.tool('guardlink_report', 'Generate a markdown threat model report with Mermaid diagram. Also writes threat-model.json alongside.', {
|
|
261
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
262
|
+
output: z.string().describe('Output filename (default: threat-model.md)').default('threat-model.md'),
|
|
263
|
+
}, async ({ root, output }) => {
|
|
264
|
+
const { model } = await getModel(root);
|
|
265
|
+
if (model.annotations_parsed === 0) {
|
|
266
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'No annotations found.' }) }] };
|
|
267
|
+
}
|
|
268
|
+
const { writeFile } = await import('node:fs/promises');
|
|
269
|
+
const { resolve } = await import('node:path');
|
|
270
|
+
const report = generateReport(model);
|
|
271
|
+
await writeFile(resolve(root, output), report + '\n');
|
|
272
|
+
const jsonFile = output.replace(/\.md$/, '.json');
|
|
273
|
+
await writeFile(resolve(root, jsonFile), JSON.stringify(model, null, 2) + '\n');
|
|
274
|
+
return {
|
|
275
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
276
|
+
report: output,
|
|
277
|
+
json: jsonFile,
|
|
278
|
+
annotations: model.annotations_parsed,
|
|
279
|
+
exposures: model.exposures.length,
|
|
280
|
+
}) }],
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
// ── Tool: guardlink_dashboard ──
|
|
284
|
+
server.tool('guardlink_dashboard', 'Generate an interactive HTML threat model dashboard with diagrams, charts, code annotations, and heatmap.', {
|
|
285
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
286
|
+
output: z.string().describe('Output filename (default: threat-dashboard.html)').default('threat-dashboard.html'),
|
|
287
|
+
}, async ({ root, output }) => {
|
|
288
|
+
const { model } = await getModel(root);
|
|
289
|
+
if (model.annotations_parsed === 0) {
|
|
290
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'No annotations found.' }) }] };
|
|
291
|
+
}
|
|
292
|
+
const { writeFile } = await import('node:fs/promises');
|
|
293
|
+
const { resolve } = await import('node:path');
|
|
294
|
+
const analyses = loadThreatReportsForDashboard(root);
|
|
295
|
+
const html = generateDashboardHTML(model, root, analyses);
|
|
296
|
+
await writeFile(resolve(root, output), html);
|
|
297
|
+
return {
|
|
298
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
299
|
+
dashboard: output,
|
|
300
|
+
annotations: model.annotations_parsed,
|
|
301
|
+
exposures: model.exposures.length,
|
|
302
|
+
}) }],
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
// ── Tool: guardlink_sarif ──
|
|
306
|
+
server.tool('guardlink_sarif', 'Export findings as SARIF 2.1.0 for GitHub Advanced Security, VS Code, and other SARIF consumers.', {
|
|
307
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
308
|
+
output: z.string().describe('Output filename (default: guardlink.sarif.json)').default('guardlink.sarif.json'),
|
|
309
|
+
}, async ({ root, output }) => {
|
|
310
|
+
invalidateCache();
|
|
311
|
+
const { model, diagnostics } = await getModel(root);
|
|
312
|
+
const { writeFile } = await import('node:fs/promises');
|
|
313
|
+
const { resolve } = await import('node:path');
|
|
314
|
+
const sarif = generateSarif(model, diagnostics, [], { includeDiagnostics: true, includeDanglingRefs: true });
|
|
315
|
+
await writeFile(resolve(root, output), JSON.stringify(sarif, null, 2) + '\n');
|
|
316
|
+
const resultCount = sarif.runs[0]?.results?.length ?? 0;
|
|
317
|
+
return {
|
|
318
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
319
|
+
sarif: output,
|
|
320
|
+
results: resultCount,
|
|
321
|
+
}) }],
|
|
322
|
+
};
|
|
323
|
+
});
|
|
324
|
+
// ── Tool: guardlink_diff ──
|
|
325
|
+
server.tool('guardlink_diff', 'Compare the current threat model against a git ref (commit, branch, tag). Shows added/removed/changed annotations, new unmitigated exposures.', {
|
|
326
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
327
|
+
ref: z.string().describe('Git ref to compare against (e.g. HEAD~1, main, v1.0)').default('HEAD~1'),
|
|
328
|
+
}, async ({ root, ref }) => {
|
|
329
|
+
try {
|
|
330
|
+
const { model: current } = await getModel(root);
|
|
331
|
+
const previous = await parseAtRef(root, ref, 'unknown');
|
|
332
|
+
const diff = diffModels(previous, current);
|
|
333
|
+
return {
|
|
334
|
+
content: [{ type: 'text', text: JSON.stringify(diff, null, 2) }],
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: 'text', text: JSON.stringify({ error: err.message }) }],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
// ── Tool: guardlink_threat_reports ──
|
|
344
|
+
server.tool('guardlink_threat_reports', 'List saved AI threat reports from .guardlink/threat-reports/ (and legacy .guardlink/analyses/). Returns filename, framework, timestamp, and model used.', {
|
|
345
|
+
root: z.string().describe('Project root directory').default('.'),
|
|
346
|
+
}, async ({ root }) => {
|
|
347
|
+
const reports = listThreatReports(root);
|
|
348
|
+
return {
|
|
349
|
+
content: [{ type: 'text', text: JSON.stringify(reports, null, 2) }],
|
|
350
|
+
};
|
|
351
|
+
});
|
|
352
|
+
// ── Resource: guardlink://model ──
|
|
353
|
+
server.resource('threat-model', 'guardlink://model', { description: 'Full ThreatModel JSON for the current project' }, async () => {
|
|
354
|
+
const { model } = await getModel(cachedRoot || '.');
|
|
355
|
+
return {
|
|
356
|
+
contents: [{ uri: 'guardlink://model', mimeType: 'application/json', text: JSON.stringify(model, null, 2) }],
|
|
357
|
+
};
|
|
358
|
+
});
|
|
359
|
+
// ── Resource: guardlink://definitions ──
|
|
360
|
+
server.resource('definitions', 'guardlink://definitions', { description: 'All defined assets, threats, and controls with their IDs' }, async () => {
|
|
361
|
+
const { model } = await getModel(cachedRoot || '.');
|
|
362
|
+
const defs = {
|
|
363
|
+
assets: model.assets.map(a => ({ id: a.id, path: a.path.join('.'), description: a.description })),
|
|
364
|
+
threats: model.threats.map(t => ({ id: t.id, name: t.canonical_name, severity: t.severity, description: t.description })),
|
|
365
|
+
controls: model.controls.map(c => ({ id: c.id, name: c.canonical_name, description: c.description })),
|
|
366
|
+
};
|
|
367
|
+
return {
|
|
368
|
+
contents: [{ uri: 'guardlink://definitions', mimeType: 'application/json', text: JSON.stringify(defs, null, 2) }],
|
|
369
|
+
};
|
|
370
|
+
});
|
|
371
|
+
// ── Resource: guardlink://unmitigated ──
|
|
372
|
+
server.resource('unmitigated', 'guardlink://unmitigated', { description: 'List of unmitigated exposures — assets exposed to threats with no @mitigates or @accepts' }, async () => {
|
|
373
|
+
const { model } = await getModel(cachedRoot || '.');
|
|
374
|
+
const covered = new Set();
|
|
375
|
+
for (const m of model.mitigations)
|
|
376
|
+
covered.add(`${m.asset}::${m.threat}`);
|
|
377
|
+
for (const a of model.acceptances)
|
|
378
|
+
covered.add(`${a.asset}::${a.threat}`);
|
|
379
|
+
const unmitigated = model.exposures
|
|
380
|
+
.filter(e => !covered.has(`${e.asset}::${e.threat}`))
|
|
381
|
+
.map(e => ({ asset: e.asset, threat: e.threat, severity: e.severity, file: e.location.file, line: e.location.line }));
|
|
382
|
+
return {
|
|
383
|
+
contents: [{ uri: 'guardlink://unmitigated', mimeType: 'application/json', text: JSON.stringify(unmitigated, null, 2) }],
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
return server;
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Suggest — Annotation suggestion engine.
|
|
3
|
+
*
|
|
4
|
+
* Analyzes code for patterns that warrant security annotations:
|
|
5
|
+
* - Function names suggesting security-relevant operations
|
|
6
|
+
* - Dangerous imports/patterns (eval, exec, SQL, file I/O, crypto)
|
|
7
|
+
* - HTTP handlers, auth checks, input parsing
|
|
8
|
+
* - Missing annotations on files that handle sensitive data
|
|
9
|
+
*
|
|
10
|
+
* Designed for both file-based and diff-based analysis (§8.2).
|
|
11
|
+
*
|
|
12
|
+
* @exposes #suggest to #path-traversal [high] cwe:CWE-22 -- "Reads files from user-specified paths for analysis"
|
|
13
|
+
* @exposes #suggest to #prompt-injection [medium] cwe:CWE-77 -- "Suggestion output may be fed back to LLM agents"
|
|
14
|
+
* @accepts #prompt-injection on #suggest -- "Suggestions are intended for LLM consumption"
|
|
15
|
+
* @mitigates #suggest against #path-traversal using #path-validation -- "join() combines root with relative file paths"
|
|
16
|
+
* @flows #mcp -> #suggest via suggestAnnotations -- "MCP tool passes file path from agent request"
|
|
17
|
+
* @flows #suggest -> #mcp via suggestions -- "Suggestions returned to calling agent"
|
|
18
|
+
*/
|
|
19
|
+
import type { ThreatModel } from '../types/index.js';
|
|
20
|
+
export interface SuggestOptions {
|
|
21
|
+
root: string;
|
|
22
|
+
model: ThreatModel;
|
|
23
|
+
file?: string;
|
|
24
|
+
diff?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Suggestion {
|
|
27
|
+
file: string;
|
|
28
|
+
line?: number;
|
|
29
|
+
annotation: string;
|
|
30
|
+
reason: string;
|
|
31
|
+
confidence: 'high' | 'medium' | 'low';
|
|
32
|
+
category: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function suggestAnnotations(opts: SuggestOptions): Promise<Suggestion[]>;
|
|
35
|
+
//# sourceMappingURL=suggest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggest.d.ts","sourceRoot":"","sources":["../../src/mcp/suggest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAwBpF"}
|