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,268 @@
|
|
|
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 { readFileSync, existsSync } from 'node:fs';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
export async function suggestAnnotations(opts) {
|
|
22
|
+
const suggestions = [];
|
|
23
|
+
if (opts.diff) {
|
|
24
|
+
suggestFromDiff(opts.diff, opts.model, suggestions);
|
|
25
|
+
}
|
|
26
|
+
else if (opts.file) {
|
|
27
|
+
const fullPath = join(opts.root, opts.file);
|
|
28
|
+
if (existsSync(fullPath)) {
|
|
29
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
30
|
+
suggestFromFile(opts.file, content, opts.model, suggestions);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Deduplicate and sort by confidence
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
const confOrder = { high: 0, medium: 1, low: 2 };
|
|
36
|
+
return suggestions
|
|
37
|
+
.filter(s => {
|
|
38
|
+
const key = `${s.file}:${s.line}:${s.annotation}`;
|
|
39
|
+
if (seen.has(key))
|
|
40
|
+
return false;
|
|
41
|
+
seen.add(key);
|
|
42
|
+
return true;
|
|
43
|
+
})
|
|
44
|
+
.sort((a, b) => confOrder[a.confidence] - confOrder[b.confidence]);
|
|
45
|
+
}
|
|
46
|
+
const PATTERNS = [
|
|
47
|
+
// SQL / database
|
|
48
|
+
{
|
|
49
|
+
regex: /(?:execute|query|raw_sql|cursor\.execute|\.query\(|knex\.|sequelize\.|prisma\.)\s*\(/i,
|
|
50
|
+
category: 'exposure',
|
|
51
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #sqli with Insufficient input validation`,
|
|
52
|
+
reason: 'Database query detected — potential SQL injection if inputs are not parameterized',
|
|
53
|
+
confidence: 'high',
|
|
54
|
+
},
|
|
55
|
+
// Command execution
|
|
56
|
+
{
|
|
57
|
+
regex: /(?:exec|spawn|execSync|child_process|subprocess|os\.system|os\.popen|Runtime\.exec)\s*\(/i,
|
|
58
|
+
category: 'exposure',
|
|
59
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #cmd-injection with Unsanitized command arguments`,
|
|
60
|
+
reason: 'Command execution detected — potential command injection',
|
|
61
|
+
confidence: 'high',
|
|
62
|
+
},
|
|
63
|
+
// File I/O with user input
|
|
64
|
+
{
|
|
65
|
+
regex: /(?:readFile|writeFile|open\(|fopen|fs\.read|Path\.resolve|path\.join).*(?:req\.|request\.|params|query|body)/i,
|
|
66
|
+
category: 'exposure',
|
|
67
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #path-traversal with User-controlled file path`,
|
|
68
|
+
reason: 'File operation with user-influenced path — potential path traversal',
|
|
69
|
+
confidence: 'high',
|
|
70
|
+
},
|
|
71
|
+
// eval / dynamic code
|
|
72
|
+
{
|
|
73
|
+
regex: /(?:eval\(|new\s+Function\(|exec\(|compile\(|setInterval\(|setTimeout\().*(?:req|input|user|param|body)/i,
|
|
74
|
+
category: 'exposure',
|
|
75
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #code-injection with Dynamic code execution`,
|
|
76
|
+
reason: 'Dynamic code execution with potential user input',
|
|
77
|
+
confidence: 'high',
|
|
78
|
+
},
|
|
79
|
+
// Auth/login handlers
|
|
80
|
+
{
|
|
81
|
+
regex: /(?:def\s+login|function\s+login|authenticate|verify_password|check_credentials|signIn)/i,
|
|
82
|
+
category: 'asset',
|
|
83
|
+
annotation: (_m, f) => `@asset ${assetFromFile(f)} -- "Authentication handler"`,
|
|
84
|
+
reason: 'Authentication-related function — should be declared as security-relevant asset',
|
|
85
|
+
confidence: 'medium',
|
|
86
|
+
},
|
|
87
|
+
// Input validation / sanitization
|
|
88
|
+
{
|
|
89
|
+
regex: /(?:sanitize|validate|escape|htmlEscape|xss|dompurify|bleach|strip_tags)/i,
|
|
90
|
+
category: 'mitigation',
|
|
91
|
+
annotation: (_m, f) => `@control Input_Validation (#input-validation) -- "Sanitizes user input"`,
|
|
92
|
+
reason: 'Input validation/sanitization detected — should be documented as a control',
|
|
93
|
+
confidence: 'medium',
|
|
94
|
+
},
|
|
95
|
+
// CORS configuration
|
|
96
|
+
{
|
|
97
|
+
regex: /(?:cors|Access-Control-Allow-Origin|allowed_origins)/i,
|
|
98
|
+
category: 'mitigation',
|
|
99
|
+
annotation: (_m, f) => `@control CORS_Policy (#cors-policy) -- "Restricts cross-origin requests"`,
|
|
100
|
+
reason: 'CORS configuration detected',
|
|
101
|
+
confidence: 'medium',
|
|
102
|
+
},
|
|
103
|
+
// Rate limiting
|
|
104
|
+
{
|
|
105
|
+
regex: /(?:rate.?limit|throttle|RateLimiter|express-rate-limit|slowapi)/i,
|
|
106
|
+
category: 'mitigation',
|
|
107
|
+
annotation: (_m, f) => `@control Rate_Limiting (#rate-limit) -- "Limits request frequency"`,
|
|
108
|
+
reason: 'Rate limiting detected',
|
|
109
|
+
confidence: 'medium',
|
|
110
|
+
},
|
|
111
|
+
// Crypto / hashing
|
|
112
|
+
{
|
|
113
|
+
regex: /(?:bcrypt|scrypt|argon2|pbkdf2|hashlib|crypto\.createHash|md5|sha256)/i,
|
|
114
|
+
category: 'mitigation',
|
|
115
|
+
annotation: (_m, f) => `@control Crypto_Hashing (#crypto-hash) -- "Cryptographic hashing for sensitive data"`,
|
|
116
|
+
reason: 'Cryptographic hashing detected',
|
|
117
|
+
confidence: 'medium',
|
|
118
|
+
},
|
|
119
|
+
// HTTP handlers
|
|
120
|
+
{
|
|
121
|
+
regex: /(?:@app\.(?:get|post|put|delete|patch)|router\.(?:get|post|put|delete)|@GetMapping|@PostMapping|@RequestMapping)/i,
|
|
122
|
+
category: 'flow',
|
|
123
|
+
annotation: (_m, f) => `@handles ${assetFromFile(f)} -- "HTTP request handler"`,
|
|
124
|
+
reason: 'HTTP endpoint handler — represents an entry point for user data',
|
|
125
|
+
confidence: 'medium',
|
|
126
|
+
},
|
|
127
|
+
// Secrets / credentials
|
|
128
|
+
{
|
|
129
|
+
regex: /(?:API_KEY|SECRET_KEY|PASSWORD|TOKEN|PRIVATE_KEY|AWS_ACCESS|DATABASE_URL)\s*[=:]/i,
|
|
130
|
+
category: 'data_handling',
|
|
131
|
+
annotation: (_m, f) => `@data ${assetFromFile(f)} stores secrets -- "Contains credentials or API keys"`,
|
|
132
|
+
reason: 'Hardcoded secret or credential reference detected',
|
|
133
|
+
confidence: 'high',
|
|
134
|
+
},
|
|
135
|
+
// Deserialization
|
|
136
|
+
{
|
|
137
|
+
regex: /(?:pickle\.load|yaml\.load\(|yaml\.unsafe_load|JSON\.parse|deserialize|unmarshal|ObjectInputStream)/i,
|
|
138
|
+
category: 'exposure',
|
|
139
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #unsafe-deser with Deserialization of untrusted data`,
|
|
140
|
+
reason: 'Deserialization detected — potential unsafe deserialization if input is untrusted',
|
|
141
|
+
confidence: 'medium',
|
|
142
|
+
},
|
|
143
|
+
// SSRF patterns
|
|
144
|
+
{
|
|
145
|
+
regex: /(?:fetch|requests\.get|urllib|http\.get|axios|HttpClient).*(?:req\.|request\.|params|query|body|url)/i,
|
|
146
|
+
category: 'exposure',
|
|
147
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #ssrf with User-controlled URL`,
|
|
148
|
+
reason: 'HTTP request with user-influenced URL — potential SSRF',
|
|
149
|
+
confidence: 'medium',
|
|
150
|
+
},
|
|
151
|
+
// Template rendering (XSS)
|
|
152
|
+
{
|
|
153
|
+
regex: /(?:render_template|innerHTML|dangerouslySetInnerHTML|v-html|ng-bind-html|\|safe\b|mark_safe)/i,
|
|
154
|
+
category: 'exposure',
|
|
155
|
+
annotation: (_m, f) => `@exposes ${assetFromFile(f)} to #xss with Unescaped output rendering`,
|
|
156
|
+
reason: 'Unsafe HTML rendering detected — potential XSS',
|
|
157
|
+
confidence: 'high',
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
// ─── File analysis ───────────────────────────────────────────────────
|
|
161
|
+
function suggestFromFile(file, content, model, out) {
|
|
162
|
+
// Skip definition files and non-source
|
|
163
|
+
if (file.includes('.guardlink/') || file.includes('node_modules/'))
|
|
164
|
+
return;
|
|
165
|
+
const lines = content.split('\n');
|
|
166
|
+
// Check if file already has annotations
|
|
167
|
+
const hasAnnotations = lines.some(l => /@(?:asset|threat|control|exposes|mitigates|accepts|flows|boundary|handles|comment|data|shield)\b/.test(l));
|
|
168
|
+
for (let i = 0; i < lines.length; i++) {
|
|
169
|
+
const line = lines[i];
|
|
170
|
+
for (const pattern of PATTERNS) {
|
|
171
|
+
const match = line.match(pattern.regex);
|
|
172
|
+
if (match) {
|
|
173
|
+
out.push({
|
|
174
|
+
file,
|
|
175
|
+
line: i + 1,
|
|
176
|
+
annotation: pattern.annotation(match, file),
|
|
177
|
+
reason: pattern.reason,
|
|
178
|
+
confidence: hasAnnotations ? pattern.confidence : lowerConfidence(pattern.confidence),
|
|
179
|
+
category: pattern.category,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Post-pass: suggest @comment on security-relevant functions with no nearby annotations or suggestions
|
|
185
|
+
const FUNC_RE = /(?:(?:export\s+)?(?:async\s+)?function\s+(\w+)|(?:export\s+)?class\s+(\w+)|def\s+(\w+)|fn\s+(\w+)|func\s+(\w+))/i;
|
|
186
|
+
const SEC_KEYWORDS = /auth|login|cred|token|secret|password|session|crypto|encrypt|decrypt|hash|key|cert|ssl|tls|api|admin|pay|billing|charge|invoice/i;
|
|
187
|
+
const suggestedLines = new Set(out.map(s => s.line));
|
|
188
|
+
for (let i = 0; i < lines.length; i++) {
|
|
189
|
+
const funcMatch = lines[i].match(FUNC_RE);
|
|
190
|
+
if (!funcMatch)
|
|
191
|
+
continue;
|
|
192
|
+
const funcName = funcMatch[1] || funcMatch[2] || funcMatch[3] || funcMatch[4] || funcMatch[5];
|
|
193
|
+
const lineNum = i + 1;
|
|
194
|
+
// Skip if already has a suggestion or annotation within 3 lines above
|
|
195
|
+
const hasNearby = Array.from({ length: 4 }, (_, k) => lineNum - k).some(ln => suggestedLines.has(ln) || (ln > 0 && ln <= lines.length && /@\w+/.test(lines[ln - 1])));
|
|
196
|
+
if (hasNearby)
|
|
197
|
+
continue;
|
|
198
|
+
// Only suggest for functions with security-relevant names or in security-relevant file paths
|
|
199
|
+
if (SEC_KEYWORDS.test(funcName) || SEC_KEYWORDS.test(file)) {
|
|
200
|
+
out.push({
|
|
201
|
+
file,
|
|
202
|
+
line: lineNum,
|
|
203
|
+
annotation: `@comment -- "TODO: Document security relevance of ${funcName}"`,
|
|
204
|
+
reason: `Security-relevant function '${funcName}' has no annotation — add at least @comment`,
|
|
205
|
+
confidence: 'low',
|
|
206
|
+
category: 'asset',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ─── Diff analysis ───────────────────────────────────────────────────
|
|
212
|
+
function suggestFromDiff(diff, model, out) {
|
|
213
|
+
// Parse unified diff format
|
|
214
|
+
let currentFile = '';
|
|
215
|
+
let lineNum = 0;
|
|
216
|
+
for (const line of diff.split('\n')) {
|
|
217
|
+
// File header: +++ b/path/to/file.ts
|
|
218
|
+
const fileMatch = line.match(/^\+\+\+\s+b\/(.+)/);
|
|
219
|
+
if (fileMatch) {
|
|
220
|
+
currentFile = fileMatch[1];
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// Hunk header: @@ -old,count +new,count @@
|
|
224
|
+
const hunkMatch = line.match(/^@@\s+-\d+(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);
|
|
225
|
+
if (hunkMatch) {
|
|
226
|
+
lineNum = parseInt(hunkMatch[1], 10);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
// Added lines (+ prefix)
|
|
230
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
231
|
+
const content = line.slice(1);
|
|
232
|
+
for (const pattern of PATTERNS) {
|
|
233
|
+
const match = content.match(pattern.regex);
|
|
234
|
+
if (match) {
|
|
235
|
+
out.push({
|
|
236
|
+
file: currentFile,
|
|
237
|
+
line: lineNum,
|
|
238
|
+
annotation: pattern.annotation(match, currentFile),
|
|
239
|
+
reason: `[New code] ${pattern.reason}`,
|
|
240
|
+
confidence: pattern.confidence,
|
|
241
|
+
category: pattern.category,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
lineNum++;
|
|
246
|
+
}
|
|
247
|
+
else if (!line.startsWith('-')) {
|
|
248
|
+
// Context line (no prefix) — increment line counter
|
|
249
|
+
lineNum++;
|
|
250
|
+
}
|
|
251
|
+
// Removed lines (- prefix) — don't increment
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
255
|
+
function assetFromFile(file) {
|
|
256
|
+
// Convert file path to a reasonable asset name suggestion
|
|
257
|
+
const base = file
|
|
258
|
+
.replace(/\.[^.]+$/, '') // Remove extension
|
|
259
|
+
.replace(/^src\/|^lib\/|^app\//, '') // Strip common prefixes
|
|
260
|
+
.replace(/\//g, '.'); // Dots for path segments
|
|
261
|
+
return base.split('.').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('.');
|
|
262
|
+
}
|
|
263
|
+
function lowerConfidence(c) {
|
|
264
|
+
if (c === 'high')
|
|
265
|
+
return 'medium';
|
|
266
|
+
return 'low';
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=suggest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggest.js","sourceRoot":"","sources":["../../src/mcp/suggest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment prefix stripping per §2.9.
|
|
3
|
+
* Strips the host language's comment prefix to expose the annotation text.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Strip comment prefix from a single line, returning the inner text
|
|
7
|
+
* or null if the line is not a comment.
|
|
8
|
+
*/
|
|
9
|
+
export declare function stripCommentPrefix(line: string): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Detect file's primary comment style from extension.
|
|
12
|
+
* Used for multi-line continuation detection.
|
|
13
|
+
*/
|
|
14
|
+
export declare function commentStyleForExt(ext: string): string;
|
|
15
|
+
//# sourceMappingURL=comment-strip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-strip.d.ts","sourceRoot":"","sources":["../../src/parser/comment-strip.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA+C9D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBtD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment prefix stripping per §2.9.
|
|
3
|
+
* Strips the host language's comment prefix to expose the annotation text.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Strip comment prefix from a single line, returning the inner text
|
|
7
|
+
* or null if the line is not a comment.
|
|
8
|
+
*/
|
|
9
|
+
export function stripCommentPrefix(line) {
|
|
10
|
+
const trimmed = line.trimStart();
|
|
11
|
+
// Single-line styles (order matters — longer prefixes first)
|
|
12
|
+
const singlePrefixes = [
|
|
13
|
+
'//', // C-family, Rust, Go, JS, TS
|
|
14
|
+
'#', // Python, Ruby, Bash, YAML, Terraform
|
|
15
|
+
'--', // Haskell, Lua, SQL, Ada
|
|
16
|
+
'%', // LaTeX, Erlang, MATLAB
|
|
17
|
+
';', // Lisp, Clojure, Assembly
|
|
18
|
+
'REM ', // Batch (with trailing space)
|
|
19
|
+
'REM\t',
|
|
20
|
+
"'", // VBA, VB.NET
|
|
21
|
+
];
|
|
22
|
+
for (const prefix of singlePrefixes) {
|
|
23
|
+
if (trimmed.startsWith(prefix)) {
|
|
24
|
+
return trimmed.slice(prefix.length).trimStart();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Block comment line (already inside a block)
|
|
28
|
+
// Strip leading * (Javadoc-style) or bare text in block
|
|
29
|
+
if (trimmed.startsWith('*') && !trimmed.startsWith('*/')) {
|
|
30
|
+
return trimmed.slice(1).trimStart();
|
|
31
|
+
}
|
|
32
|
+
// HTML/XML comment: <!-- ... -->
|
|
33
|
+
const htmlMatch = trimmed.match(/^<!--\s*(.*?)\s*-->$/);
|
|
34
|
+
if (htmlMatch)
|
|
35
|
+
return htmlMatch[1];
|
|
36
|
+
// Opening block comment on same line: /* ... */ or /* ...
|
|
37
|
+
const blockOpenClose = trimmed.match(/^\/\*\s*(.*?)\s*\*\/$/);
|
|
38
|
+
if (blockOpenClose)
|
|
39
|
+
return blockOpenClose[1];
|
|
40
|
+
const blockOpen = trimmed.match(/^\/\*\s*(.*)$/);
|
|
41
|
+
if (blockOpen)
|
|
42
|
+
return blockOpen[1].trimStart();
|
|
43
|
+
// Haskell block: {- ... -}
|
|
44
|
+
const haskellBlock = trimmed.match(/^\{-\s*(.*?)\s*-\}$/);
|
|
45
|
+
if (haskellBlock)
|
|
46
|
+
return haskellBlock[1];
|
|
47
|
+
// OCaml/Pascal: (* ... *)
|
|
48
|
+
const ocamlBlock = trimmed.match(/^\(\*\s*(.*?)\s*\*\)$/);
|
|
49
|
+
if (ocamlBlock)
|
|
50
|
+
return ocamlBlock[1];
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Detect file's primary comment style from extension.
|
|
55
|
+
* Used for multi-line continuation detection.
|
|
56
|
+
*/
|
|
57
|
+
export function commentStyleForExt(ext) {
|
|
58
|
+
const map = {
|
|
59
|
+
'.ts': '//', '.tsx': '//', '.js': '//', '.jsx': '//',
|
|
60
|
+
'.java': '//', '.c': '//', '.cpp': '//', '.cc': '//',
|
|
61
|
+
'.cs': '//', '.go': '//', '.rs': '//', '.swift': '//',
|
|
62
|
+
'.kt': '//', '.scala': '//', '.dart': '//',
|
|
63
|
+
'.py': '#', '.rb': '#', '.sh': '#', '.bash': '#',
|
|
64
|
+
'.yml': '#', '.yaml': '#', '.tf': '#', '.r': '#',
|
|
65
|
+
'.ex': '#', '.exs': '#', '.nim': '#', '.pl': '#',
|
|
66
|
+
'.hs': '--', '.lua': '--', '.sql': '--', '.ada': '--',
|
|
67
|
+
'.html': '<!--', '.xml': '<!--', '.svg': '<!--',
|
|
68
|
+
'.css': '/*',
|
|
69
|
+
'.tex': '%', '.erl': '%', '.m': '%',
|
|
70
|
+
'.lisp': ';', '.cl': ';', '.clj': ';', '.asm': ';',
|
|
71
|
+
'.bat': 'REM', '.cmd': 'REM',
|
|
72
|
+
'.vb': "'", '.bas': "'",
|
|
73
|
+
};
|
|
74
|
+
return map[ext.toLowerCase()] || '//';
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=comment-strip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-strip.js","sourceRoot":"","sources":["../../src/parser/comment-strip.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Parser — Public API
|
|
3
|
+
*/
|
|
4
|
+
export { parseFile, parseString } from './parse-file.js';
|
|
5
|
+
export { parseProject } from './parse-project.js';
|
|
6
|
+
export type { ParseProjectOptions } from './parse-project.js';
|
|
7
|
+
export { parseLine } from './parse-line.js';
|
|
8
|
+
export { normalizeName, resolveSeverity, unescapeDescription } from './normalize.js';
|
|
9
|
+
export { stripCommentPrefix, commentStyleForExt } from './comment-strip.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Parser — Public API
|
|
3
|
+
*/
|
|
4
|
+
export { parseFile, parseString } from './parse-file.js';
|
|
5
|
+
export { parseProject } from './parse-project.js';
|
|
6
|
+
export { parseLine } from './parse-line.js';
|
|
7
|
+
export { normalizeName, resolveSeverity, unescapeDescription } from './normalize.js';
|
|
8
|
+
export { stripCommentPrefix, commentStyleForExt } from './comment-strip.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name normalization per §2.10 of the GuardLink spec.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm:
|
|
5
|
+
* 1. Apply Unicode NFKC normalization
|
|
6
|
+
* 2. Convert to lowercase
|
|
7
|
+
* 3. Replace whitespace → underscore
|
|
8
|
+
* 4. Replace hyphens → underscore
|
|
9
|
+
* 5. Collapse consecutive underscores
|
|
10
|
+
* 6. Strip leading/trailing underscores
|
|
11
|
+
*/
|
|
12
|
+
export declare function normalizeName(name: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Severity alias resolution: P0→critical, P1→high, etc.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveSeverity(raw: string): 'critical' | 'high' | 'medium' | 'low' | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Unescape description string per §2.11.
|
|
19
|
+
* Handles \" → " and \\\\ → \\
|
|
20
|
+
*/
|
|
21
|
+
export declare function unescapeDescription(raw: string): string;
|
|
22
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/parser/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAQ/F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIvD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name normalization per §2.10 of the GuardLink spec.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm:
|
|
5
|
+
* 1. Apply Unicode NFKC normalization
|
|
6
|
+
* 2. Convert to lowercase
|
|
7
|
+
* 3. Replace whitespace → underscore
|
|
8
|
+
* 4. Replace hyphens → underscore
|
|
9
|
+
* 5. Collapse consecutive underscores
|
|
10
|
+
* 6. Strip leading/trailing underscores
|
|
11
|
+
*/
|
|
12
|
+
export function normalizeName(name) {
|
|
13
|
+
return name
|
|
14
|
+
.normalize('NFKC')
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[\s\t\u00A0]+/g, '_') // whitespace → underscore
|
|
17
|
+
.replace(/-+/g, '_') // hyphens → underscore
|
|
18
|
+
.replace(/_+/g, '_') // collapse consecutive
|
|
19
|
+
.replace(/^_|_$/g, ''); // strip leading/trailing
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Severity alias resolution: P0→critical, P1→high, etc.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveSeverity(raw) {
|
|
25
|
+
const map = {
|
|
26
|
+
p0: 'critical', critical: 'critical',
|
|
27
|
+
p1: 'high', high: 'high',
|
|
28
|
+
p2: 'medium', medium: 'medium',
|
|
29
|
+
p3: 'low', low: 'low',
|
|
30
|
+
};
|
|
31
|
+
return map[raw.toLowerCase()];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Unescape description string per §2.11.
|
|
35
|
+
* Handles \" → " and \\\\ → \\
|
|
36
|
+
*/
|
|
37
|
+
export function unescapeDescription(raw) {
|
|
38
|
+
return raw
|
|
39
|
+
.replace(/\\"/g, '"')
|
|
40
|
+
.replace(/\\\\/g, '\\');
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/parser/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI;SACR,SAAS,CAAC,MAAM,CAAC;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAE,0BAA0B;SAC1D,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAc,uBAAuB;SACxD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAc,uBAAuB;SACxD,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAW,yBAAyB;AAC/D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,GAAG,GAA2D;QAClE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU;QACpC,EAAE,EAAE,MAAM,EAAM,IAAI,EAAE,MAAM;QAC5B,EAAE,EAAE,QAAQ,EAAI,MAAM,EAAE,QAAQ;QAChC,EAAE,EAAE,KAAK,EAAO,GAAG,EAAE,KAAK;KAC3B,CAAC;IACF,OAAO,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,GAAG;SACP,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink — File-level parser.
|
|
3
|
+
* Reads source files and extracts all GuardLink annotations.
|
|
4
|
+
*
|
|
5
|
+
* @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Reads files from disk using provided file path"
|
|
6
|
+
* @comment -- "File paths are controlled by parse-project glob results, not direct user input"
|
|
7
|
+
*/
|
|
8
|
+
import type { ParseResult } from '../types/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Parse a single file and return all annotations found.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseFile(filePath: string): Promise<ParseResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a string of source code and return all annotations found.
|
|
15
|
+
* Useful for testing without file I/O.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseString(content: string, filePath?: string): ParseResult;
|
|
18
|
+
//# sourceMappingURL=parse-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-file.d.ts","sourceRoot":"","sources":["../../src/parser/parse-file.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKlF;;GAEG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGtE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAkB,GAAG,WAAW,CAgDtF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink — File-level parser.
|
|
3
|
+
* Reads source files and extracts all GuardLink annotations.
|
|
4
|
+
*
|
|
5
|
+
* @exposes #parser to #path-traversal [high] cwe:CWE-22 -- "Reads files from disk using provided file path"
|
|
6
|
+
* @comment -- "File paths are controlled by parse-project glob results, not direct user input"
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { stripCommentPrefix } from './comment-strip.js';
|
|
10
|
+
import { parseLine } from './parse-line.js';
|
|
11
|
+
import { unescapeDescription } from './normalize.js';
|
|
12
|
+
/**
|
|
13
|
+
* Parse a single file and return all annotations found.
|
|
14
|
+
*/
|
|
15
|
+
export async function parseFile(filePath) {
|
|
16
|
+
const content = await readFile(filePath, 'utf-8');
|
|
17
|
+
return parseString(content, filePath);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse a string of source code and return all annotations found.
|
|
21
|
+
* Useful for testing without file I/O.
|
|
22
|
+
*/
|
|
23
|
+
export function parseString(content, filePath = '<input>') {
|
|
24
|
+
const lines = content.split('\n');
|
|
25
|
+
const annotations = [];
|
|
26
|
+
const diagnostics = [];
|
|
27
|
+
let lastAnnotation = null;
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const lineNum = i + 1; // 1-indexed
|
|
30
|
+
const rawLine = lines[i];
|
|
31
|
+
// Strip comment prefix
|
|
32
|
+
const inner = stripCommentPrefix(rawLine);
|
|
33
|
+
if (inner === null) {
|
|
34
|
+
lastAnnotation = null;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Check for continuation line: -- "..."
|
|
38
|
+
const contMatch = inner.match(/^--\s*"((?:[^"\\]|\\.)*)"/);
|
|
39
|
+
if (contMatch && lastAnnotation) {
|
|
40
|
+
// Append to last annotation's description
|
|
41
|
+
const contDesc = unescapeDescription(contMatch[1]);
|
|
42
|
+
if (lastAnnotation.description) {
|
|
43
|
+
lastAnnotation.description += ' ' + contDesc;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
lastAnnotation.description = contDesc;
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Try to parse as annotation
|
|
51
|
+
const location = { file: filePath, line: lineNum };
|
|
52
|
+
const result = parseLine(inner, location);
|
|
53
|
+
if (result.annotation) {
|
|
54
|
+
annotations.push(result.annotation);
|
|
55
|
+
lastAnnotation = result.annotation;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
if (result.diagnostic) {
|
|
59
|
+
diagnostics.push(result.diagnostic);
|
|
60
|
+
}
|
|
61
|
+
if (!result.isContinuation) {
|
|
62
|
+
lastAnnotation = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { annotations, diagnostics, files_parsed: 1 };
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=parse-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-file.js","sourceRoot":"","sources":["../../src/parser/parse-file.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,WAAmB,SAAS;IACvE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,WAAW,GAAsB,EAAE,CAAC;IAC1C,IAAI,cAAc,GAAsB,IAAI,CAAC;IAE7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,YAAY;QACpC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEzB,uBAAuB;QACvB,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,cAAc,GAAG,IAAI,CAAC;YACtB,SAAS;QACX,CAAC;QAED,wCAAwC;QACxC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3D,IAAI,SAAS,IAAI,cAAc,EAAE,CAAC;YAChC,0CAA0C;YAC1C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,IAAI,cAAc,CAAC,WAAW,EAAE,CAAC;gBAC/B,cAAc,CAAC,WAAW,IAAI,GAAG,GAAG,QAAQ,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,WAAW,GAAG,QAAQ,CAAC;YACxC,CAAC;YACD,SAAS;QACX,CAAC;QAED,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAE1C,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACpC,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACtC,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC3B,cAAc,GAAG,IAAI,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink — Line-level annotation parser.
|
|
3
|
+
* Parses a single comment line into a typed Annotation.
|
|
4
|
+
*
|
|
5
|
+
* @exposes #parser to #redos [medium] cwe:CWE-1333 -- "Complex regex patterns run against untrusted annotation content"
|
|
6
|
+
* @mitigates #parser against #redos using #regex-anchoring -- "All patterns use ^ anchor and defined character classes"
|
|
7
|
+
* @comment -- "PATTERNS object contains all annotation regex; patterns are pre-compiled for performance"
|
|
8
|
+
*/
|
|
9
|
+
import type { Annotation, ParseDiagnostic, SourceLocation } from '../types/index.js';
|
|
10
|
+
export interface ParseLineResult {
|
|
11
|
+
annotation: Annotation | null;
|
|
12
|
+
diagnostic: ParseDiagnostic | null;
|
|
13
|
+
isContinuation: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse a single annotation line (after comment prefix has been stripped).
|
|
17
|
+
* Returns the typed annotation, a diagnostic if parsing failed, or null if
|
|
18
|
+
* the line is not an annotation.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseLine(text: string, location: SourceLocation): ParseLineResult;
|
|
21
|
+
//# sourceMappingURL=parse-line.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-line.d.ts","sourceRoot":"","sources":["../../src/parser/parse-line.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EAAE,cAAc,EAChC,MAAM,mBAAmB,CAAC;AAsE3B,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,cAAc,GACvB,eAAe,CA8KjB"}
|