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.
Files changed (172) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +344 -0
  4. package/dist/agents/config.d.ts +46 -0
  5. package/dist/agents/config.d.ts.map +1 -0
  6. package/dist/agents/config.js +189 -0
  7. package/dist/agents/config.js.map +1 -0
  8. package/dist/agents/index.d.ts +24 -0
  9. package/dist/agents/index.d.ts.map +1 -0
  10. package/dist/agents/index.js +42 -0
  11. package/dist/agents/index.js.map +1 -0
  12. package/dist/agents/launcher.d.ts +54 -0
  13. package/dist/agents/launcher.d.ts.map +1 -0
  14. package/dist/agents/launcher.js +152 -0
  15. package/dist/agents/launcher.js.map +1 -0
  16. package/dist/agents/prompts.d.ts +14 -0
  17. package/dist/agents/prompts.d.ts.map +1 -0
  18. package/dist/agents/prompts.js +120 -0
  19. package/dist/agents/prompts.js.map +1 -0
  20. package/dist/analyze/index.d.ts +80 -0
  21. package/dist/analyze/index.d.ts.map +1 -0
  22. package/dist/analyze/index.js +306 -0
  23. package/dist/analyze/index.js.map +1 -0
  24. package/dist/analyze/llm.d.ts +52 -0
  25. package/dist/analyze/llm.d.ts.map +1 -0
  26. package/dist/analyze/llm.js +295 -0
  27. package/dist/analyze/llm.js.map +1 -0
  28. package/dist/analyze/prompts.d.ts +14 -0
  29. package/dist/analyze/prompts.d.ts.map +1 -0
  30. package/dist/analyze/prompts.js +205 -0
  31. package/dist/analyze/prompts.js.map +1 -0
  32. package/dist/analyzer/index.d.ts +5 -0
  33. package/dist/analyzer/index.d.ts.map +1 -0
  34. package/dist/analyzer/index.js +5 -0
  35. package/dist/analyzer/index.js.map +1 -0
  36. package/dist/analyzer/sarif.d.ts +84 -0
  37. package/dist/analyzer/sarif.d.ts.map +1 -0
  38. package/dist/analyzer/sarif.js +149 -0
  39. package/dist/analyzer/sarif.js.map +1 -0
  40. package/dist/cli/index.d.ts +25 -0
  41. package/dist/cli/index.d.ts.map +1 -0
  42. package/dist/cli/index.js +821 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/dashboard/data.d.ts +52 -0
  45. package/dist/dashboard/data.d.ts.map +1 -0
  46. package/dist/dashboard/data.js +93 -0
  47. package/dist/dashboard/data.js.map +1 -0
  48. package/dist/dashboard/diagrams.d.ts +25 -0
  49. package/dist/dashboard/diagrams.d.ts.map +1 -0
  50. package/dist/dashboard/diagrams.js +243 -0
  51. package/dist/dashboard/diagrams.js.map +1 -0
  52. package/dist/dashboard/generate.d.ts +17 -0
  53. package/dist/dashboard/generate.d.ts.map +1 -0
  54. package/dist/dashboard/generate.js +1258 -0
  55. package/dist/dashboard/generate.js.map +1 -0
  56. package/dist/dashboard/index.d.ts +7 -0
  57. package/dist/dashboard/index.d.ts.map +1 -0
  58. package/dist/dashboard/index.js +7 -0
  59. package/dist/dashboard/index.js.map +1 -0
  60. package/dist/diff/engine.d.ts +51 -0
  61. package/dist/diff/engine.d.ts.map +1 -0
  62. package/dist/diff/engine.js +153 -0
  63. package/dist/diff/engine.js.map +1 -0
  64. package/dist/diff/format.d.ts +10 -0
  65. package/dist/diff/format.d.ts.map +1 -0
  66. package/dist/diff/format.js +111 -0
  67. package/dist/diff/format.js.map +1 -0
  68. package/dist/diff/git.d.ts +24 -0
  69. package/dist/diff/git.d.ts.map +1 -0
  70. package/dist/diff/git.js +85 -0
  71. package/dist/diff/git.js.map +1 -0
  72. package/dist/diff/index.d.ts +7 -0
  73. package/dist/diff/index.d.ts.map +1 -0
  74. package/dist/diff/index.js +7 -0
  75. package/dist/diff/index.js.map +1 -0
  76. package/dist/index.d.ts +20 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +17 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/init/detect.d.ts +42 -0
  81. package/dist/init/detect.d.ts.map +1 -0
  82. package/dist/init/detect.js +185 -0
  83. package/dist/init/detect.js.map +1 -0
  84. package/dist/init/index.d.ts +39 -0
  85. package/dist/init/index.d.ts.map +1 -0
  86. package/dist/init/index.js +228 -0
  87. package/dist/init/index.js.map +1 -0
  88. package/dist/init/picker.d.ts +32 -0
  89. package/dist/init/picker.d.ts.map +1 -0
  90. package/dist/init/picker.js +105 -0
  91. package/dist/init/picker.js.map +1 -0
  92. package/dist/init/templates.d.ts +25 -0
  93. package/dist/init/templates.d.ts.map +1 -0
  94. package/dist/init/templates.js +263 -0
  95. package/dist/init/templates.js.map +1 -0
  96. package/dist/mcp/index.d.ts +12 -0
  97. package/dist/mcp/index.d.ts.map +1 -0
  98. package/dist/mcp/index.js +18 -0
  99. package/dist/mcp/index.js.map +1 -0
  100. package/dist/mcp/lookup.d.ts +27 -0
  101. package/dist/mcp/lookup.d.ts.map +1 -0
  102. package/dist/mcp/lookup.js +282 -0
  103. package/dist/mcp/lookup.js.map +1 -0
  104. package/dist/mcp/server.d.ts +41 -0
  105. package/dist/mcp/server.d.ts.map +1 -0
  106. package/dist/mcp/server.js +388 -0
  107. package/dist/mcp/server.js.map +1 -0
  108. package/dist/mcp/suggest.d.ts +35 -0
  109. package/dist/mcp/suggest.d.ts.map +1 -0
  110. package/dist/mcp/suggest.js +268 -0
  111. package/dist/mcp/suggest.js.map +1 -0
  112. package/dist/parser/comment-strip.d.ts +15 -0
  113. package/dist/parser/comment-strip.d.ts.map +1 -0
  114. package/dist/parser/comment-strip.js +76 -0
  115. package/dist/parser/comment-strip.js.map +1 -0
  116. package/dist/parser/index.d.ts +10 -0
  117. package/dist/parser/index.d.ts.map +1 -0
  118. package/dist/parser/index.js +9 -0
  119. package/dist/parser/index.js.map +1 -0
  120. package/dist/parser/normalize.d.ts +22 -0
  121. package/dist/parser/normalize.d.ts.map +1 -0
  122. package/dist/parser/normalize.js +42 -0
  123. package/dist/parser/normalize.js.map +1 -0
  124. package/dist/parser/parse-file.d.ts +18 -0
  125. package/dist/parser/parse-file.d.ts.map +1 -0
  126. package/dist/parser/parse-file.js +68 -0
  127. package/dist/parser/parse-file.js.map +1 -0
  128. package/dist/parser/parse-line.d.ts +21 -0
  129. package/dist/parser/parse-line.d.ts.map +1 -0
  130. package/dist/parser/parse-line.js +230 -0
  131. package/dist/parser/parse-line.js.map +1 -0
  132. package/dist/parser/parse-project.d.ts +31 -0
  133. package/dist/parser/parse-project.d.ts.map +1 -0
  134. package/dist/parser/parse-project.js +281 -0
  135. package/dist/parser/parse-project.js.map +1 -0
  136. package/dist/report/index.d.ts +6 -0
  137. package/dist/report/index.d.ts.map +1 -0
  138. package/dist/report/index.js +6 -0
  139. package/dist/report/index.js.map +1 -0
  140. package/dist/report/mermaid.d.ts +15 -0
  141. package/dist/report/mermaid.d.ts.map +1 -0
  142. package/dist/report/mermaid.js +260 -0
  143. package/dist/report/mermaid.js.map +1 -0
  144. package/dist/report/report.d.ts +16 -0
  145. package/dist/report/report.d.ts.map +1 -0
  146. package/dist/report/report.js +211 -0
  147. package/dist/report/report.js.map +1 -0
  148. package/dist/tui/commands.d.ts +42 -0
  149. package/dist/tui/commands.d.ts.map +1 -0
  150. package/dist/tui/commands.js +1216 -0
  151. package/dist/tui/commands.js.map +1 -0
  152. package/dist/tui/config.d.ts +27 -0
  153. package/dist/tui/config.d.ts.map +1 -0
  154. package/dist/tui/config.js +27 -0
  155. package/dist/tui/config.js.map +1 -0
  156. package/dist/tui/format.d.ts +63 -0
  157. package/dist/tui/format.d.ts.map +1 -0
  158. package/dist/tui/format.js +253 -0
  159. package/dist/tui/format.js.map +1 -0
  160. package/dist/tui/index.d.ts +18 -0
  161. package/dist/tui/index.d.ts.map +1 -0
  162. package/dist/tui/index.js +470 -0
  163. package/dist/tui/index.js.map +1 -0
  164. package/dist/tui/input.d.ts +63 -0
  165. package/dist/tui/input.d.ts.map +1 -0
  166. package/dist/tui/input.js +454 -0
  167. package/dist/tui/input.js.map +1 -0
  168. package/dist/types/index.d.ts +254 -0
  169. package/dist/types/index.d.ts.map +1 -0
  170. package/dist/types/index.js +6 -0
  171. package/dist/types/index.js.map +1 -0
  172. package/package.json +97 -0
@@ -0,0 +1,306 @@
1
+ /**
2
+ * GuardLink Threat Reports — AI-powered threat model analysis.
3
+ *
4
+ * Serializes the threat model, sends it to an LLM with a framework-
5
+ * specific prompt, streams the response, and saves timestamped results
6
+ * to .guardlink/threat-reports/.
7
+ *
8
+ * @exposes #llm-client to #arbitrary-write [high] cwe:CWE-73 -- "Writes threat reports to .guardlink/threat-reports/"
9
+ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "Serialized threat model embedded in LLM prompt"
10
+ * @accepts #prompt-injection on #llm-client -- "Core feature: threat model serialized as LLM prompt for analysis"
11
+ * @mitigates #llm-client against #arbitrary-write using #path-validation -- "Reports written to fixed .guardlink/threat-reports/ subdirectory"
12
+ * @flows #parser -> #llm-client via ThreatModel -- "Parsed model data serialized for LLM analysis"
13
+ * @flows #llm-client -> Filesystem via writeFileSync -- "Analysis results saved as markdown files"
14
+ * @handles internal on #llm-client -- "Processes security-sensitive threat model for AI analysis"
15
+ */
16
+ import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { FRAMEWORK_LABELS, FRAMEWORK_PROMPTS, buildUserMessage } from './prompts.js';
19
+ import { chatCompletion } from './llm.js';
20
+ export { FRAMEWORK_LABELS, FRAMEWORK_PROMPTS, buildUserMessage } from './prompts.js';
21
+ export { buildConfig, autoDetectConfig } from './llm.js';
22
+ // ─── Serialization ───────────────────────────────────────────────────
23
+ /**
24
+ * Serialize the threat model to a compact representation for LLM context.
25
+ * Strips empty arrays and location details to save tokens.
26
+ */
27
+ export function serializeModel(model) {
28
+ const compact = {
29
+ project: model.project,
30
+ annotations: model.annotations_parsed,
31
+ source_files: model.source_files,
32
+ };
33
+ // Only include non-empty sections
34
+ if (model.assets.length)
35
+ compact.assets = model.assets.map(a => ({
36
+ path: a.path.join('.'), id: a.id, description: a.description,
37
+ }));
38
+ if (model.threats.length)
39
+ compact.threats = model.threats.map(t => ({
40
+ name: t.name, id: t.id, severity: t.severity,
41
+ refs: t.external_refs.length ? t.external_refs : undefined,
42
+ description: t.description,
43
+ }));
44
+ if (model.controls.length)
45
+ compact.controls = model.controls.map(c => ({
46
+ name: c.name, id: c.id, description: c.description,
47
+ }));
48
+ if (model.mitigations.length)
49
+ compact.mitigations = model.mitigations.map(m => ({
50
+ asset: m.asset, threat: m.threat, control: m.control,
51
+ description: m.description, file: m.location.file,
52
+ }));
53
+ if (model.exposures.length)
54
+ compact.exposures = model.exposures.map(e => ({
55
+ asset: e.asset, threat: e.threat, severity: e.severity,
56
+ refs: e.external_refs.length ? e.external_refs : undefined,
57
+ description: e.description, file: e.location.file,
58
+ }));
59
+ if (model.acceptances.length)
60
+ compact.acceptances = model.acceptances.map(a => ({
61
+ asset: a.asset, threat: a.threat, description: a.description,
62
+ }));
63
+ if (model.transfers.length)
64
+ compact.transfers = model.transfers.map(t => ({
65
+ threat: t.threat, source: t.source, target: t.target,
66
+ }));
67
+ if (model.flows.length)
68
+ compact.flows = model.flows.map(f => ({
69
+ source: f.source, target: f.target, mechanism: f.mechanism,
70
+ }));
71
+ if (model.boundaries.length)
72
+ compact.boundaries = model.boundaries.map(b => ({
73
+ a: b.asset_a, b: b.asset_b, id: b.id, description: b.description,
74
+ }));
75
+ if (model.data_handling.length)
76
+ compact.data_handling = model.data_handling.map(h => ({
77
+ classification: h.classification, asset: h.asset,
78
+ }));
79
+ if (model.assumptions.length)
80
+ compact.assumptions = model.assumptions.map(a => ({
81
+ asset: a.asset, description: a.description,
82
+ }));
83
+ if (model.comments.length)
84
+ compact.comments = model.comments.map(c => ({
85
+ description: c.description, file: c.location.file,
86
+ }));
87
+ if (model.validations.length)
88
+ compact.validations = model.validations.map(v => ({
89
+ control: v.control, asset: v.asset,
90
+ }));
91
+ // Coverage summary
92
+ compact.coverage = {
93
+ total_symbols: model.coverage.total_symbols,
94
+ annotated: model.coverage.annotated_symbols,
95
+ percent: model.coverage.coverage_percent,
96
+ };
97
+ // Unmitigated exposures summary
98
+ const mitigatedSet = new Set();
99
+ for (const m of model.mitigations)
100
+ mitigatedSet.add(`${m.asset}::${m.threat}`);
101
+ for (const a of model.acceptances)
102
+ mitigatedSet.add(`${a.asset}::${a.threat}`);
103
+ const unmitigated = model.exposures.filter(e => !mitigatedSet.has(`${e.asset}::${e.threat}`));
104
+ if (unmitigated.length) {
105
+ compact.unmitigated_exposures = unmitigated.map(e => ({
106
+ asset: e.asset, threat: e.threat, severity: e.severity,
107
+ }));
108
+ }
109
+ return JSON.stringify(compact, null, 2);
110
+ }
111
+ /**
112
+ * Compact serialization for MCP agent mode.
113
+ *
114
+ * Designed to minimize token usage (~2-3k tokens vs ~10k for full)
115
+ * while giving the agent everything it needs:
116
+ * - Stats summary (one line)
117
+ * - Asset list (compact)
118
+ * - ALL unmitigated exposures (the actionable stuff)
119
+ * - Threat severity index (deduped)
120
+ * - Flows & boundaries (structural context)
121
+ * - Data handling classifications
122
+ *
123
+ * Omits: resolved mitigations, acceptances, working controls,
124
+ * full descriptions (capped at 80 chars), per-exposure file paths,
125
+ * comments, validations, assumptions (low signal for analysis).
126
+ *
127
+ * The agent can call guardlink_parse or read guardlink://model
128
+ * for full detail if needed.
129
+ */
130
+ export function serializeModelCompact(model) {
131
+ // Compute unmitigated set
132
+ const covered = new Set();
133
+ for (const m of model.mitigations)
134
+ covered.add(`${m.asset}::${m.threat}`);
135
+ for (const a of model.acceptances)
136
+ covered.add(`${a.asset}::${a.threat}`);
137
+ const unmitigated = model.exposures.filter(e => !covered.has(`${e.asset}::${e.threat}`));
138
+ const cap = (s, n = 80) => s && s.length > n ? s.slice(0, n - 1) + '…' : s;
139
+ // Severity counts
140
+ const sevCounts = {};
141
+ for (const e of unmitigated) {
142
+ const s = e.severity || 'unset';
143
+ sevCounts[s] = (sevCounts[s] || 0) + 1;
144
+ }
145
+ const compact = {
146
+ project: model.project,
147
+ summary: `${model.annotations_parsed} annotations, ${model.assets.length} assets, ${model.threats.length} threats, ${model.controls.length} controls, ${model.exposures.length} exposures (${unmitigated.length} unmitigated), ${model.mitigations.length} mitigations`,
148
+ severity_breakdown: sevCounts,
149
+ };
150
+ // Assets — just path + id, no descriptions
151
+ if (model.assets.length) {
152
+ compact.assets = model.assets.map(a => a.id || a.path.join('.'));
153
+ }
154
+ // Unmitigated exposures — grouped by asset for compactness
155
+ if (unmitigated.length) {
156
+ const byAsset = {};
157
+ for (const e of unmitigated) {
158
+ const key = e.asset;
159
+ if (!byAsset[key])
160
+ byAsset[key] = [];
161
+ const entry = { threat: e.threat, severity: e.severity };
162
+ if (e.external_refs.length)
163
+ entry.refs = e.external_refs;
164
+ if (e.description)
165
+ entry.desc = cap(e.description);
166
+ byAsset[key].push(entry);
167
+ }
168
+ compact.unmitigated = byAsset;
169
+ }
170
+ // Threat index — deduped, severity + refs only
171
+ if (model.threats.length) {
172
+ compact.threats = model.threats.map(t => {
173
+ const entry = { id: t.id, severity: t.severity };
174
+ if (t.external_refs.length)
175
+ entry.refs = t.external_refs;
176
+ return entry;
177
+ });
178
+ }
179
+ // Flows & boundaries — structural context for attack path analysis
180
+ if (model.flows.length) {
181
+ compact.flows = model.flows.map(f => `${f.source} → ${f.target}${f.mechanism ? ' via ' + f.mechanism : ''}`);
182
+ }
183
+ if (model.boundaries.length) {
184
+ compact.boundaries = model.boundaries.map(b => `${b.asset_a} | ${b.asset_b}${b.description ? ': ' + cap(b.description, 40) : ''}`);
185
+ }
186
+ // Data handling — classification matters for compliance analysis
187
+ if (model.data_handling.length) {
188
+ compact.data_handling = model.data_handling.map(h => `${h.asset}: ${h.classification}`);
189
+ }
190
+ // Mitigation count per asset (not full details — just "how defended is each asset?")
191
+ if (model.mitigations.length) {
192
+ const mitByAsset = {};
193
+ for (const m of model.mitigations)
194
+ mitByAsset[m.asset] = (mitByAsset[m.asset] || 0) + 1;
195
+ compact.mitigations_per_asset = mitByAsset;
196
+ }
197
+ return JSON.stringify(compact, null, 2);
198
+ }
199
+ // ─── Threat report generation ────────────────────────────────────────
200
+ /** Storage directory for threat reports (new path) */
201
+ const THREAT_REPORTS_DIR = 'threat-reports';
202
+ /** Legacy storage directory (read fallback) */
203
+ const LEGACY_ANALYSES_DIR = 'analyses';
204
+ export async function generateThreatReport(opts) {
205
+ const { root, model, framework, llmConfig, customPrompt } = opts;
206
+ const modelJson = serializeModel(model);
207
+ const systemPrompt = FRAMEWORK_PROMPTS[framework];
208
+ const userMessage = buildUserMessage(modelJson, framework, customPrompt);
209
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
210
+ // Call LLM
211
+ const response = await chatCompletion(llmConfig, systemPrompt, userMessage, opts.stream ? opts.onChunk : undefined);
212
+ // Save to .guardlink/threat-reports/
213
+ const reportsDir = join(root, '.guardlink', THREAT_REPORTS_DIR);
214
+ if (!existsSync(reportsDir)) {
215
+ mkdirSync(reportsDir, { recursive: true });
216
+ }
217
+ const filename = `${timestamp}-${framework}.md`;
218
+ const filepath = join(reportsDir, filename);
219
+ const header = `---
220
+ framework: ${framework}
221
+ label: ${FRAMEWORK_LABELS[framework]}
222
+ model: ${response.model}
223
+ timestamp: ${new Date().toISOString()}
224
+ input_tokens: ${response.inputTokens || 'unknown'}
225
+ output_tokens: ${response.outputTokens || 'unknown'}
226
+ project: ${model.project}
227
+ annotations: ${model.annotations_parsed}
228
+ ---
229
+
230
+ # ${FRAMEWORK_LABELS[framework]}
231
+
232
+ > Generated by \`guardlink threat-report ${framework}\` on ${new Date().toISOString().slice(0, 10)}
233
+ > Model: ${response.model} | Project: ${model.project} | Annotations: ${model.annotations_parsed}
234
+
235
+ `;
236
+ writeFileSync(filepath, header + response.content + '\n');
237
+ return {
238
+ framework,
239
+ label: FRAMEWORK_LABELS[framework],
240
+ content: response.content,
241
+ model: response.model,
242
+ timestamp,
243
+ savedTo: `.guardlink/${THREAT_REPORTS_DIR}/${filename}`,
244
+ inputTokens: response.inputTokens,
245
+ outputTokens: response.outputTokens,
246
+ };
247
+ }
248
+ /** Read .md files from a .guardlink subdirectory */
249
+ function readReportsFromDir(dirPath, dirName) {
250
+ if (!existsSync(dirPath))
251
+ return [];
252
+ return readdirSync(dirPath)
253
+ .filter(f => f.endsWith('.md'))
254
+ .map(filename => {
255
+ const match = filename.match(/^(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})-(\w+)\.md$/);
256
+ const framework = match?.[2] || 'unknown';
257
+ const timestamp = match?.[1]?.replace(/T/, ' ').replace(/-/g, (m, offset) => offset > 9 ? ':' : '-') || filename;
258
+ let model;
259
+ try {
260
+ const content = readFileSync(join(dirPath, filename), 'utf-8');
261
+ const modelMatch = content.match(/^model:\s*(.+)$/m);
262
+ if (modelMatch)
263
+ model = modelMatch[1].trim();
264
+ }
265
+ catch { /* ignore */ }
266
+ return {
267
+ filename,
268
+ framework,
269
+ timestamp,
270
+ label: FRAMEWORK_LABELS[framework] || framework,
271
+ model,
272
+ dirName,
273
+ };
274
+ });
275
+ }
276
+ export function listThreatReports(root) {
277
+ // Read from new path first, then legacy, merge and dedup by filename
278
+ const newDir = join(root, '.guardlink', THREAT_REPORTS_DIR);
279
+ const legacyDir = join(root, '.guardlink', LEGACY_ANALYSES_DIR);
280
+ const reports = readReportsFromDir(newDir, THREAT_REPORTS_DIR);
281
+ const legacy = readReportsFromDir(legacyDir, LEGACY_ANALYSES_DIR);
282
+ // Merge: new path takes precedence if same filename exists in both
283
+ const seen = new Set(reports.map(r => r.filename));
284
+ for (const l of legacy) {
285
+ if (!seen.has(l.filename))
286
+ reports.push(l);
287
+ }
288
+ return reports.sort((a, b) => b.filename.localeCompare(a.filename));
289
+ }
290
+ const MAX_REPORTS_IN_DASHBOARD = 50;
291
+ export function loadThreatReportsForDashboard(root) {
292
+ const entries = listThreatReports(root).slice(0, MAX_REPORTS_IN_DASHBOARD);
293
+ const result = [];
294
+ for (const entry of entries) {
295
+ const dir = join(root, '.guardlink', entry.dirName || THREAT_REPORTS_DIR);
296
+ try {
297
+ const raw = readFileSync(join(dir, entry.filename), 'utf-8');
298
+ const content = raw.replace(/^---[\s\S]*?---\n*/, '').trim();
299
+ if (content)
300
+ result.push({ ...entry, content });
301
+ }
302
+ catch { /* skip unreadable files */ }
303
+ }
304
+ return result;
305
+ }
306
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyze/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * GuardLink Threat Reports — Lightweight LLM client using raw fetch.
3
+ *
4
+ * Supports:
5
+ * - Anthropic Messages API (claude-sonnet-4-5-20250929, etc.)
6
+ * - OpenAI-compatible Chat Completions (GPT-4o, DeepSeek, OpenRouter)
7
+ *
8
+ * Zero dependencies — uses Node 20+ built-in fetch.
9
+ *
10
+ * @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "Reads API keys from environment variables"
11
+ * @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "Makes HTTP requests to configurable provider URLs"
12
+ * @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "Sends threat model content as LLM prompt"
13
+ * @accepts #prompt-injection on #llm-client -- "Core feature: threat model data is sent to LLM for analysis"
14
+ * @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded to known providers"
15
+ * @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys read from env, not logged"
16
+ * @handles secrets on #llm-client -- "API keys held in memory during request lifecycle"
17
+ * @boundary between #llm-client and External_LLM_APIs (#llm-boundary) -- "HTTP requests cross network trust boundary to external AI providers"
18
+ * @flows #llm-client -> External_LLM_APIs via fetch -- "HTTP POST with auth headers and prompt payload"
19
+ * @flows External_LLM_APIs -> #llm-client via response -- "Streaming or complete response from LLM provider"
20
+ */
21
+ export type LLMProvider = 'anthropic' | 'openai' | 'openrouter' | 'deepseek';
22
+ export interface LLMConfig {
23
+ provider: LLMProvider;
24
+ model: string;
25
+ apiKey: string;
26
+ baseUrl?: string;
27
+ maxTokens?: number;
28
+ }
29
+ export interface LLMResponse {
30
+ content: string;
31
+ model: string;
32
+ inputTokens?: number;
33
+ outputTokens?: number;
34
+ }
35
+ /**
36
+ * Auto-detect provider from environment variables.
37
+ * Returns null if no API key found.
38
+ */
39
+ export declare function autoDetectConfig(): LLMConfig | null;
40
+ /**
41
+ * Build config from explicit flags + env vars.
42
+ */
43
+ export declare function buildConfig(opts: {
44
+ provider?: string;
45
+ model?: string;
46
+ apiKey?: string;
47
+ }): LLMConfig | null;
48
+ /**
49
+ * Send a message to the LLM and return the response.
50
+ */
51
+ export declare function chatCompletion(config: LLMConfig, systemPrompt: string, userMessage: string, onChunk?: (text: string) => void): Promise<LLMResponse>;
52
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/analyze/llm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;AAE7E,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgBD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,GAAG,IAAI,CA+BnD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,SAAS,GAAG,IAAI,CA2BnB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC/B,OAAO,CAAC,WAAW,CAAC,CAMtB"}