@owasp-aghast/aghast 0.8.4 → 0.9.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-config.d.ts.map +1 -1
- package/dist/build-config.js +101 -2
- package/dist/build-config.js.map +1 -1
- package/dist/check-library.d.ts +25 -0
- package/dist/check-library.d.ts.map +1 -1
- package/dist/check-library.js +165 -0
- package/dist/check-library.js.map +1 -1
- package/dist/ci-metadata.d.ts +42 -0
- package/dist/ci-metadata.d.ts.map +1 -0
- package/dist/ci-metadata.js +131 -0
- package/dist/ci-metadata.js.map +1 -0
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/concurrency.d.ts +18 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +39 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/cost-tracker.d.ts +45 -0
- package/dist/cost-tracker.d.ts.map +1 -0
- package/dist/cost-tracker.js +56 -0
- package/dist/cost-tracker.js.map +1 -0
- package/dist/discoveries/glob-discovery.d.ts +21 -0
- package/dist/discoveries/glob-discovery.d.ts.map +1 -0
- package/dist/discoveries/glob-discovery.js +215 -0
- package/dist/discoveries/glob-discovery.js.map +1 -0
- package/dist/discoveries/script-discovery.d.ts +117 -0
- package/dist/discoveries/script-discovery.d.ts.map +1 -0
- package/dist/discoveries/script-discovery.js +593 -0
- package/dist/discoveries/script-discovery.js.map +1 -0
- package/dist/docs-url.d.ts +14 -0
- package/dist/docs-url.d.ts.map +1 -0
- package/dist/docs-url.js +17 -0
- package/dist/docs-url.js.map +1 -0
- package/dist/error-codes.d.ts +12 -1
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +16 -2
- package/dist/error-codes.js.map +1 -1
- package/dist/formatters/csv-formatter.d.ts +12 -1
- package/dist/formatters/csv-formatter.d.ts.map +1 -1
- package/dist/formatters/csv-formatter.js +64 -2
- package/dist/formatters/csv-formatter.js.map +1 -1
- package/dist/formatters/html-formatter.d.ts.map +1 -1
- package/dist/formatters/html-formatter.js +43 -3
- package/dist/formatters/html-formatter.js.map +1 -1
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +2 -0
- package/dist/formatters/index.js.map +1 -1
- package/dist/formatters/markdown-formatter.d.ts +61 -0
- package/dist/formatters/markdown-formatter.d.ts.map +1 -0
- package/dist/formatters/markdown-formatter.js +557 -0
- package/dist/formatters/markdown-formatter.js.map +1 -0
- package/dist/formatters/sarif-formatter.d.ts +7 -0
- package/dist/formatters/sarif-formatter.d.ts.map +1 -1
- package/dist/formatters/sarif-formatter.js +80 -0
- package/dist/formatters/sarif-formatter.js.map +1 -1
- package/dist/formatters/types.d.ts +24 -0
- package/dist/formatters/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +342 -9
- package/dist/index.js.map +1 -1
- package/dist/issue-file-writer.d.ts +21 -0
- package/dist/issue-file-writer.d.ts.map +1 -0
- package/dist/issue-file-writer.js +307 -0
- package/dist/issue-file-writer.js.map +1 -0
- package/dist/judge.d.ts +62 -0
- package/dist/judge.d.ts.map +1 -0
- package/dist/judge.js +305 -0
- package/dist/judge.js.map +1 -0
- package/dist/mock-agent-provider.d.ts +3 -0
- package/dist/mock-agent-provider.d.ts.map +1 -1
- package/dist/mock-agent-provider.js +13 -0
- package/dist/mock-agent-provider.js.map +1 -1
- package/dist/new-check.d.ts.map +1 -1
- package/dist/new-check.js +322 -13
- package/dist/new-check.js.map +1 -1
- package/dist/opencode-provider.d.ts.map +1 -1
- package/dist/opencode-provider.js +33 -0
- package/dist/opencode-provider.js.map +1 -1
- package/dist/repo-scan.d.ts +80 -0
- package/dist/repo-scan.d.ts.map +1 -0
- package/dist/repo-scan.js +250 -0
- package/dist/repo-scan.js.map +1 -0
- package/dist/result-handlers/pr-comment-handler.d.ts +136 -0
- package/dist/result-handlers/pr-comment-handler.d.ts.map +1 -0
- package/dist/result-handlers/pr-comment-handler.js +381 -0
- package/dist/result-handlers/pr-comment-handler.js.map +1 -0
- package/dist/retry.d.ts +128 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +261 -0
- package/dist/retry.js.map +1 -0
- package/dist/runtime-config.d.ts.map +1 -1
- package/dist/runtime-config.js +62 -0
- package/dist/runtime-config.js.map +1 -1
- package/dist/scan-runner.d.ts +31 -22
- package/dist/scan-runner.d.ts.map +1 -1
- package/dist/scan-runner.js +145 -100
- package/dist/scan-runner.js.map +1 -1
- package/dist/semgrep-runner.js +6 -4
- package/dist/semgrep-runner.js.map +1 -1
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +4 -1
- package/dist/stats.js.map +1 -1
- package/dist/types.d.ts +149 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown output formatter — produces a human-readable security report.
|
|
3
|
+
* See SPECIFICATION.md Appendix E.3.1.
|
|
4
|
+
*
|
|
5
|
+
* Sections (in order):
|
|
6
|
+
* 1. Header — Title, date, AI provider/model, repository info
|
|
7
|
+
* 2. Executive Summary — One-paragraph overview of the scan outcome
|
|
8
|
+
* 3. Summary Table — All checks with PASS/FAIL/FLAG/ERROR status
|
|
9
|
+
* 4. Detailed Findings — Failed checks with descriptions, snippets, recs
|
|
10
|
+
* 5. Flagged Items — Checks needing human review (only when present)
|
|
11
|
+
* 6. Errors — Checks with ERROR status (only when present)
|
|
12
|
+
* 7. Statistics — Totals for the scan
|
|
13
|
+
* 8. CI Metadata — Job URL / branch / pipeline info (only when set)
|
|
14
|
+
*/
|
|
15
|
+
/** File-extension to fenced-code-block language tag. Default is `text`. */
|
|
16
|
+
const EXTENSION_LANGUAGE_MAP = {
|
|
17
|
+
ts: 'ts',
|
|
18
|
+
tsx: 'tsx',
|
|
19
|
+
js: 'js',
|
|
20
|
+
jsx: 'jsx',
|
|
21
|
+
mjs: 'js',
|
|
22
|
+
cjs: 'js',
|
|
23
|
+
py: 'python',
|
|
24
|
+
rb: 'ruby',
|
|
25
|
+
go: 'go',
|
|
26
|
+
rs: 'rust',
|
|
27
|
+
java: 'java',
|
|
28
|
+
kt: 'kotlin',
|
|
29
|
+
scala: 'scala',
|
|
30
|
+
cs: 'csharp',
|
|
31
|
+
c: 'c',
|
|
32
|
+
h: 'c',
|
|
33
|
+
cpp: 'cpp',
|
|
34
|
+
cc: 'cpp',
|
|
35
|
+
hpp: 'cpp',
|
|
36
|
+
php: 'php',
|
|
37
|
+
swift: 'swift',
|
|
38
|
+
sh: 'bash',
|
|
39
|
+
bash: 'bash',
|
|
40
|
+
zsh: 'bash',
|
|
41
|
+
ps1: 'powershell',
|
|
42
|
+
yml: 'yaml',
|
|
43
|
+
yaml: 'yaml',
|
|
44
|
+
json: 'json',
|
|
45
|
+
toml: 'toml',
|
|
46
|
+
xml: 'xml',
|
|
47
|
+
html: 'html',
|
|
48
|
+
htm: 'html',
|
|
49
|
+
css: 'css',
|
|
50
|
+
scss: 'scss',
|
|
51
|
+
sql: 'sql',
|
|
52
|
+
md: 'markdown',
|
|
53
|
+
};
|
|
54
|
+
/** Resolves the fenced-code-block language tag from a file path. */
|
|
55
|
+
export function languageForFile(filePath) {
|
|
56
|
+
const lastDot = filePath.lastIndexOf('.');
|
|
57
|
+
if (lastDot < 0 || lastDot === filePath.length - 1)
|
|
58
|
+
return 'text';
|
|
59
|
+
const ext = filePath.slice(lastDot + 1).toLowerCase();
|
|
60
|
+
return EXTENSION_LANGUAGE_MAP[ext] ?? 'text';
|
|
61
|
+
}
|
|
62
|
+
/** Returns the longest backtick run in `code` so we can pick a longer fence. */
|
|
63
|
+
function chooseFence(code) {
|
|
64
|
+
// Fast path: no backticks in body → standard 3-backtick fence.
|
|
65
|
+
if (code.indexOf('`') === -1)
|
|
66
|
+
return '```';
|
|
67
|
+
let longest = 0;
|
|
68
|
+
const re = /`+/g;
|
|
69
|
+
let match;
|
|
70
|
+
while ((match = re.exec(code)) !== null) {
|
|
71
|
+
if (match[0].length > longest)
|
|
72
|
+
longest = match[0].length;
|
|
73
|
+
}
|
|
74
|
+
return '`'.repeat(Math.max(3, longest + 1));
|
|
75
|
+
}
|
|
76
|
+
/** Wraps code in a fenced block with a language tag, escaping nested fences safely. */
|
|
77
|
+
export function fencedCode(code, language) {
|
|
78
|
+
const fence = chooseFence(code);
|
|
79
|
+
// Strip a single trailing newline (LF or CRLF) so we control spacing inside
|
|
80
|
+
// the block. Without CRLF handling, Windows-line-ending snippets would leave
|
|
81
|
+
// a stray \r before the closing fence.
|
|
82
|
+
const body = code.replace(/\r?\n$/, '');
|
|
83
|
+
return `${fence}${language}\n${body}\n${fence}`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Wraps `value` in a backtick fence long enough to survive any backticks
|
|
87
|
+
* already inside `value`. Per CommonMark, an inline-code span uses a backtick
|
|
88
|
+
* run of length N around a body that contains no run of length N — minimum
|
|
89
|
+
* length 1 (unlike fenced code blocks, which require minimum 3). Pad with a
|
|
90
|
+
* leading/trailing space if the body itself starts or ends with a backtick.
|
|
91
|
+
* Newlines are collapsed to spaces because inline-code spans must be
|
|
92
|
+
* single-line (and table cells must not contain raw newlines).
|
|
93
|
+
*/
|
|
94
|
+
export function inlineCode(value) {
|
|
95
|
+
// CommonMark/GFM treat a bare CR (not just CRLF/LF) as a line ending — see
|
|
96
|
+
// escapeMarkdownText/escapeInlineText/escapeTableCell's identical fix — so
|
|
97
|
+
// collapse it here too. `value` is often AI-response-controlled (e.g.
|
|
98
|
+
// `issue.file`); an uncollapsed bare `\r` would split the surrounding
|
|
99
|
+
// Markdown into two physical lines before the backtick span can close,
|
|
100
|
+
// letting a leading `#` on the second line render as a real heading.
|
|
101
|
+
const flat = value.replace(/\r\n?|\n/g, ' ');
|
|
102
|
+
// Compute longest backtick run inline (don't reuse chooseFence — its
|
|
103
|
+
// minimum is 3 for block fences, but inline-code minimum is 1).
|
|
104
|
+
let longest = 0;
|
|
105
|
+
const re = /`+/g;
|
|
106
|
+
let match;
|
|
107
|
+
while ((match = re.exec(flat)) !== null) {
|
|
108
|
+
if (match[0].length > longest)
|
|
109
|
+
longest = match[0].length;
|
|
110
|
+
}
|
|
111
|
+
const fence = '`'.repeat(longest + 1);
|
|
112
|
+
const padStart = flat.startsWith('`') ? ' ' : '';
|
|
113
|
+
const padEnd = flat.endsWith('`') ? ' ' : '';
|
|
114
|
+
return `${fence}${padStart}${flat}${padEnd}${fence}`;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Escapes characters so a string is safe inside a Markdown table cell.
|
|
118
|
+
*
|
|
119
|
+
* Order matters:
|
|
120
|
+
* 1. Backslashes first, so subsequent `\|` insertions aren't mis-parsed
|
|
121
|
+
* (input `a\|b` would otherwise become `a\\|b`, which renders as a
|
|
122
|
+
* literal `\` followed by an UNESCAPED `|` — splitting the cell).
|
|
123
|
+
* 2. Pipes next.
|
|
124
|
+
* 3. Backticks (escape so they don't open inline-code spans inside the
|
|
125
|
+
* cell — a single backtick in a `checkName` would otherwise bleed
|
|
126
|
+
* across columns).
|
|
127
|
+
* 4. Collapse newlines to spaces — table cells must be single-line.
|
|
128
|
+
*/
|
|
129
|
+
function escapeTableCell(value) {
|
|
130
|
+
return value
|
|
131
|
+
.replace(/\\/g, '\\\\')
|
|
132
|
+
.replace(/\|/g, '\\|')
|
|
133
|
+
.replace(/`/g, '\\`')
|
|
134
|
+
// CommonMark/GFM treat a bare CR (not just CRLF/LF) as a line ending — see
|
|
135
|
+
// escapeMarkdownText's identical fix — so collapse it here too, not just
|
|
136
|
+
// `\r?\n`, or a lone `\r` would survive uncollapsed into a multi-line cell.
|
|
137
|
+
.replace(/\r\n?|\n/g, ' ');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Escapes AI-authored free text (issue `description` / `recommendation`) for
|
|
141
|
+
* safe rendering as a Markdown *block*.
|
|
142
|
+
*
|
|
143
|
+
* Threat model: these fields come from the LLM's analysis of the scanned
|
|
144
|
+
* repository, whose source can contain attacker-crafted strings. Rendered raw
|
|
145
|
+
* they can inject active HTML that executes when the report is viewed on GitHub,
|
|
146
|
+
* a wiki, or any Markdown viewer permitting inline HTML (`<script>`,
|
|
147
|
+
* `<img onerror=...>`), and can break the report's own structure (table cells,
|
|
148
|
+
* headings, code fences, lists, blockquotes). The HTML formatter already defends
|
|
149
|
+
* the same fields via `escapeHtml`; this is the Markdown-side equivalent.
|
|
150
|
+
*
|
|
151
|
+
* Unlike {@link escapeInlineText}, newlines are *preserved* — these are prose
|
|
152
|
+
* paragraphs, not single-line bullets — so the escaping is applied per line:
|
|
153
|
+
* 1. Inline pass: backslash-escape every character that can open inline
|
|
154
|
+
* formatting or a raw HTML tag (`\` first so we don't re-escape our own
|
|
155
|
+
* escapes). Escaping `<` is what neutralises the inline-HTML vector — per
|
|
156
|
+
* CommonMark/GFM, `\<script>` renders as literal text.
|
|
157
|
+
* 2. Block pass: backslash-escape a leading marker (after optional
|
|
158
|
+
* indentation) that would open a block construct — ATX heading (`#`),
|
|
159
|
+
* list/thematic-break (`-`/`+`), setext underline (`=`), or an ordered-list
|
|
160
|
+
* marker (`1.` / `1)`). Blockquote (`>`) and fences (`` ` ``/`~`) are
|
|
161
|
+
* already handled by the inline pass.
|
|
162
|
+
*/
|
|
163
|
+
export function escapeMarkdownText(value) {
|
|
164
|
+
return value
|
|
165
|
+
// CommonMark/GFM treat CRLF, LF, *and a bare CR* as line endings — fold
|
|
166
|
+
// all three to `\n` before splitting, or a lone `\r` would slip through
|
|
167
|
+
// unsplit and its trailing content would bypass the block-marker escapes
|
|
168
|
+
// below despite a compliant renderer treating it as a new line.
|
|
169
|
+
.replace(/\r\n?/g, '\n')
|
|
170
|
+
.split('\n')
|
|
171
|
+
.map((line) => {
|
|
172
|
+
const inline = line
|
|
173
|
+
.replace(/\\/g, '\\\\')
|
|
174
|
+
.replace(/[`*_[\]<>|~]/g, (m) => `\\${m}`);
|
|
175
|
+
return inline
|
|
176
|
+
.replace(/^(\s*)([#=+-])/, '$1\\$2')
|
|
177
|
+
.replace(/^(\s*)(\d+)([.)])/, '$1$2\\$3');
|
|
178
|
+
})
|
|
179
|
+
.join('\n');
|
|
180
|
+
}
|
|
181
|
+
/** Sentence-case label for a status (e.g. `PASS` → `Passed`). */
|
|
182
|
+
function statusLabel(status) {
|
|
183
|
+
switch (status) {
|
|
184
|
+
case 'PASS': return 'Passed';
|
|
185
|
+
case 'FAIL': return 'Failed';
|
|
186
|
+
case 'FLAG': return 'Flagged';
|
|
187
|
+
case 'ERROR': return 'Error';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function renderHeader(results) {
|
|
191
|
+
const lines = [];
|
|
192
|
+
lines.push('# Security Scan Report');
|
|
193
|
+
lines.push('');
|
|
194
|
+
lines.push(`- **Scan ID:** ${inlineCode(results.scanId)}`);
|
|
195
|
+
lines.push(`- **Date:** ${results.timestamp}`);
|
|
196
|
+
lines.push(`- **aghast version:** ${results.version}`);
|
|
197
|
+
const models = results.agentProvider.models.length > 0
|
|
198
|
+
? results.agentProvider.models.join(', ')
|
|
199
|
+
: '(none)';
|
|
200
|
+
lines.push(`- **Agent provider:** ${results.agentProvider.name} (model: ${models})`);
|
|
201
|
+
lines.push('');
|
|
202
|
+
lines.push(...renderRepository(results.repository));
|
|
203
|
+
return lines.join('\n');
|
|
204
|
+
}
|
|
205
|
+
function renderRepository(repo) {
|
|
206
|
+
const lines = [];
|
|
207
|
+
lines.push('## Repository');
|
|
208
|
+
lines.push('');
|
|
209
|
+
lines.push(`- **Path:** ${inlineCode(repo.path)}`);
|
|
210
|
+
// Wrap the remote URL in `<...>` (CommonMark autolink syntax) so it
|
|
211
|
+
// remains clickable while the angle-bracket form prevents underscores or
|
|
212
|
+
// other markdown-special characters in the URL from being interpreted as
|
|
213
|
+
// formatting. If the URL itself contains `<` or `>` (illegal per RFC 3986
|
|
214
|
+
// but possible in pathological inputs) we fall back to inline-code so the
|
|
215
|
+
// angle-bracket pair stays balanced.
|
|
216
|
+
if (repo.remoteUrl) {
|
|
217
|
+
const url = repo.remoteUrl;
|
|
218
|
+
const safeAutoLink = !url.includes('<') && !url.includes('>') && !/\s/.test(url);
|
|
219
|
+
lines.push(`- **Remote URL:** ${safeAutoLink ? `<${url}>` : inlineCode(url)}`);
|
|
220
|
+
}
|
|
221
|
+
if (repo.branch)
|
|
222
|
+
lines.push(`- **Branch:** ${inlineCode(repo.branch)}`);
|
|
223
|
+
if (repo.commit)
|
|
224
|
+
lines.push(`- **Commit:** ${inlineCode(repo.commit)}`);
|
|
225
|
+
lines.push(`- **Git repository:** ${repo.isGitRepository ? 'yes' : 'no'}`);
|
|
226
|
+
return lines;
|
|
227
|
+
}
|
|
228
|
+
function renderExecutiveSummary(results) {
|
|
229
|
+
const { summary } = results;
|
|
230
|
+
let outcome;
|
|
231
|
+
if (summary.totalChecks === 0) {
|
|
232
|
+
outcome = 'No checks were applicable to this repository.';
|
|
233
|
+
}
|
|
234
|
+
else if (summary.failedChecks > 0 && summary.errorChecks > 0) {
|
|
235
|
+
outcome = `The scan found **${summary.failedChecks} failing** check(s) with a total of **${summary.totalIssues} issue(s)**, and **${summary.errorChecks}** check(s) errored before completing.`;
|
|
236
|
+
}
|
|
237
|
+
else if (summary.failedChecks > 0) {
|
|
238
|
+
outcome = `The scan found **${summary.failedChecks} failing** check(s) with a total of **${summary.totalIssues} issue(s)** that require attention.`;
|
|
239
|
+
}
|
|
240
|
+
else if (summary.errorChecks > 0) {
|
|
241
|
+
outcome = `The scan completed with **${summary.errorChecks}** check(s) in an error state and no failing checks.`;
|
|
242
|
+
}
|
|
243
|
+
else if (summary.flaggedChecks > 0) {
|
|
244
|
+
outcome = `The scan completed with **${summary.flaggedChecks}** check(s) flagged for human review and no failing checks.`;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
outcome = `All ${summary.totalChecks} check(s) passed with no issues detected.`;
|
|
248
|
+
}
|
|
249
|
+
return `## Executive Summary\n\n${outcome}`;
|
|
250
|
+
}
|
|
251
|
+
function renderSummaryTable(results) {
|
|
252
|
+
const lines = [];
|
|
253
|
+
lines.push('## Summary Table');
|
|
254
|
+
lines.push('');
|
|
255
|
+
if (results.checks.length === 0) {
|
|
256
|
+
lines.push('_No checks were executed._');
|
|
257
|
+
return lines.join('\n');
|
|
258
|
+
}
|
|
259
|
+
lines.push('| Check ID | Name | Status | Issues | Time (ms) |');
|
|
260
|
+
lines.push('| --- | --- | --- | --- | --- |');
|
|
261
|
+
for (const check of results.checks) {
|
|
262
|
+
lines.push(`| ${inlineCode(check.checkId)} `
|
|
263
|
+
+ `| ${escapeTableCell(check.checkName)} `
|
|
264
|
+
+ `| ${check.status} `
|
|
265
|
+
+ `| ${check.issuesFound} `
|
|
266
|
+
+ `| ${check.executionTime} |`);
|
|
267
|
+
}
|
|
268
|
+
return lines.join('\n');
|
|
269
|
+
}
|
|
270
|
+
function renderDetailedFindings(results) {
|
|
271
|
+
const failingChecks = results.checks.filter((c) => c.status === 'FAIL');
|
|
272
|
+
const lines = [];
|
|
273
|
+
lines.push('## Detailed Findings');
|
|
274
|
+
lines.push('');
|
|
275
|
+
if (failingChecks.length === 0) {
|
|
276
|
+
lines.push('_No failing checks._');
|
|
277
|
+
return lines.join('\n');
|
|
278
|
+
}
|
|
279
|
+
for (const check of failingChecks) {
|
|
280
|
+
lines.push(`### ${check.checkName} (${inlineCode(check.checkId)})`);
|
|
281
|
+
lines.push('');
|
|
282
|
+
lines.push(`- **Status:** ${statusLabel(check.status)}`);
|
|
283
|
+
lines.push(`- **Issues found:** ${check.issuesFound}`);
|
|
284
|
+
if (typeof check.targetsAnalyzed === 'number') {
|
|
285
|
+
lines.push(`- **Targets analyzed:** ${check.targetsAnalyzed}`);
|
|
286
|
+
}
|
|
287
|
+
lines.push('');
|
|
288
|
+
const issues = results.issues.filter((i) => i.checkId === check.checkId);
|
|
289
|
+
if (issues.length === 0) {
|
|
290
|
+
lines.push('_No issue details were attached to this check._');
|
|
291
|
+
lines.push('');
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
issues.forEach((issue, idx) => {
|
|
295
|
+
lines.push(...renderIssue(issue, idx + 1));
|
|
296
|
+
lines.push('');
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
// Trim trailing blank line so section terminates cleanly.
|
|
300
|
+
while (lines.length > 0 && lines[lines.length - 1] === '')
|
|
301
|
+
lines.pop();
|
|
302
|
+
return lines.join('\n');
|
|
303
|
+
}
|
|
304
|
+
function renderIssue(issue, ordinal) {
|
|
305
|
+
const lines = [];
|
|
306
|
+
// Note: issue ordinal restarts at 1 inside each failing check. The H4
|
|
307
|
+
// headings are scoped under their check's H3 parent so the structure is
|
|
308
|
+
// clear when reading top-to-bottom; consumers that flatten H4s (e.g. TOC
|
|
309
|
+
// generators) will see duplicate "Issue 1" anchors and should disambiguate
|
|
310
|
+
// by including the parent H3 in the anchor.
|
|
311
|
+
lines.push(`#### Issue ${ordinal}: ${inlineCode(issue.file)} lines ${issue.startLine}-${issue.endLine}`);
|
|
312
|
+
lines.push('');
|
|
313
|
+
if (issue.severity)
|
|
314
|
+
lines.push(`- **Severity:** ${issue.severity}`);
|
|
315
|
+
if (issue.confidence)
|
|
316
|
+
lines.push(`- **Confidence:** ${issue.confidence}`);
|
|
317
|
+
lines.push(`- **Location:** ${inlineCode(issue.file)}:${issue.startLine}-${issue.endLine}`);
|
|
318
|
+
lines.push('');
|
|
319
|
+
lines.push('**Description:**');
|
|
320
|
+
lines.push('');
|
|
321
|
+
// AI-authored free text — escape so crafted repo content can't inject active
|
|
322
|
+
// HTML or break the report's Markdown structure (see escapeMarkdownText).
|
|
323
|
+
lines.push(escapeMarkdownText(issue.description));
|
|
324
|
+
if (issue.codeSnippet) {
|
|
325
|
+
lines.push('');
|
|
326
|
+
lines.push('**Code:**');
|
|
327
|
+
lines.push('');
|
|
328
|
+
lines.push(fencedCode(issue.codeSnippet, languageForFile(issue.file)));
|
|
329
|
+
}
|
|
330
|
+
if (issue.dataFlow && issue.dataFlow.length > 0) {
|
|
331
|
+
lines.push('');
|
|
332
|
+
lines.push('**Data flow:**');
|
|
333
|
+
lines.push('');
|
|
334
|
+
issue.dataFlow.forEach((step, i) => {
|
|
335
|
+
lines.push(`${i + 1}. ${inlineCode(step.file)}:${step.lineNumber} - ${step.label}`);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
if (issue.recommendation) {
|
|
339
|
+
lines.push('');
|
|
340
|
+
lines.push('**Recommendation:**');
|
|
341
|
+
lines.push('');
|
|
342
|
+
// Same AI-authored free text as description — escape it identically.
|
|
343
|
+
lines.push(escapeMarkdownText(issue.recommendation));
|
|
344
|
+
}
|
|
345
|
+
if (issue.judge) {
|
|
346
|
+
lines.push('');
|
|
347
|
+
lines.push('**Judge verdict:**');
|
|
348
|
+
lines.push('');
|
|
349
|
+
const confidence = `${Math.round(issue.judge.confidence * 100)}% confidence`;
|
|
350
|
+
lines.push(`- **Verdict:** ${issue.judge.verdict} (${confidence})`);
|
|
351
|
+
lines.push(`- **Model:** ${inlineCode(issue.judge.model)}`);
|
|
352
|
+
if (issue.judge.rationale) {
|
|
353
|
+
// Rationale is model-authored free text; escape it so a stray backtick or
|
|
354
|
+
// pipe cannot break out of the bullet and corrupt the rest of the report.
|
|
355
|
+
lines.push(`- **Rationale:** ${escapeInlineText(issue.judge.rationale)}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return lines;
|
|
359
|
+
}
|
|
360
|
+
function renderFlaggedItems(results) {
|
|
361
|
+
const flagged = results.checks.filter((c) => c.status === 'FLAG');
|
|
362
|
+
if (flagged.length === 0)
|
|
363
|
+
return null;
|
|
364
|
+
const lines = [];
|
|
365
|
+
lines.push('## Flagged Items');
|
|
366
|
+
lines.push('');
|
|
367
|
+
lines.push('The following checks completed but have been flagged for human review.');
|
|
368
|
+
lines.push('');
|
|
369
|
+
lines.push('| Check ID | Name | Issues |');
|
|
370
|
+
lines.push('| --- | --- | --- |');
|
|
371
|
+
for (const check of flagged) {
|
|
372
|
+
lines.push(`| ${inlineCode(check.checkId)} `
|
|
373
|
+
+ `| ${escapeTableCell(check.checkName)} `
|
|
374
|
+
+ `| ${check.issuesFound} |`);
|
|
375
|
+
}
|
|
376
|
+
return lines.join('\n');
|
|
377
|
+
}
|
|
378
|
+
function renderErrors(results) {
|
|
379
|
+
const errored = results.checks.filter((c) => c.status === 'ERROR');
|
|
380
|
+
if (errored.length === 0)
|
|
381
|
+
return null;
|
|
382
|
+
const lines = [];
|
|
383
|
+
lines.push('## Errors');
|
|
384
|
+
lines.push('');
|
|
385
|
+
lines.push('The following checks failed to execute and produced no findings.');
|
|
386
|
+
lines.push('');
|
|
387
|
+
// Use the same H3 shape as Detailed Findings (`### Name (id)`) — no leading
|
|
388
|
+
// ordinal — so the report's heading style is consistent across sections.
|
|
389
|
+
errored.forEach((check) => {
|
|
390
|
+
lines.push(`### ${check.checkName} (${inlineCode(check.checkId)})`);
|
|
391
|
+
lines.push('');
|
|
392
|
+
if (check.error) {
|
|
393
|
+
lines.push('**Error message:**');
|
|
394
|
+
lines.push('');
|
|
395
|
+
lines.push(fencedCode(check.error, 'text'));
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
lines.push('_No error message was captured._');
|
|
399
|
+
}
|
|
400
|
+
if (check.rawAiResponse) {
|
|
401
|
+
lines.push('');
|
|
402
|
+
lines.push('**Raw agent response:**');
|
|
403
|
+
lines.push('');
|
|
404
|
+
lines.push(fencedCode(check.rawAiResponse, 'text'));
|
|
405
|
+
}
|
|
406
|
+
lines.push('');
|
|
407
|
+
});
|
|
408
|
+
while (lines.length > 0 && lines[lines.length - 1] === '')
|
|
409
|
+
lines.pop();
|
|
410
|
+
return lines.join('\n');
|
|
411
|
+
}
|
|
412
|
+
function renderStatistics(results) {
|
|
413
|
+
const { summary } = results;
|
|
414
|
+
const lines = [];
|
|
415
|
+
lines.push('## Statistics');
|
|
416
|
+
lines.push('');
|
|
417
|
+
lines.push(`- **Total checks:** ${summary.totalChecks}`);
|
|
418
|
+
lines.push(`- **Passed:** ${summary.passedChecks}`);
|
|
419
|
+
lines.push(`- **Failed:** ${summary.failedChecks}`);
|
|
420
|
+
lines.push(`- **Flagged:** ${summary.flaggedChecks}`);
|
|
421
|
+
lines.push(`- **Errors:** ${summary.errorChecks}`);
|
|
422
|
+
lines.push(`- **Total issues:** ${summary.totalIssues}`);
|
|
423
|
+
lines.push(`- **Execution time (ms):** ${results.executionTime}`);
|
|
424
|
+
lines.push(`- **Start:** ${results.startTime}`);
|
|
425
|
+
lines.push(`- **End:** ${results.endTime}`);
|
|
426
|
+
if (results.tokenUsage) {
|
|
427
|
+
lines.push(`- **Tokens:** total ${results.tokenUsage.totalTokens.toLocaleString('en-US')} `
|
|
428
|
+
+ `(input ${results.tokenUsage.inputTokens.toLocaleString('en-US')}, `
|
|
429
|
+
+ `output ${results.tokenUsage.outputTokens.toLocaleString('en-US')})`);
|
|
430
|
+
}
|
|
431
|
+
// Cost sits with tokens rather than under its own heading: it is the same
|
|
432
|
+
// question ("what did this run consume?") and the reader is already here.
|
|
433
|
+
const cost = results.metadata?.cost;
|
|
434
|
+
if (cost) {
|
|
435
|
+
lines.push(`- **Estimated cost:** ${formatCost(cost.totalCostUsd, cost.currency)}`);
|
|
436
|
+
}
|
|
437
|
+
return lines.join('\n');
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Format a cost for display. Sub-cent runs are common with cheap models, and
|
|
441
|
+
* rounding them to "$0.00" reads as "free" rather than "very small", so those
|
|
442
|
+
* get four decimal places instead of two.
|
|
443
|
+
*/
|
|
444
|
+
function formatCost(amount, currency) {
|
|
445
|
+
const decimals = amount > 0 && amount < 0.01 ? 4 : 2;
|
|
446
|
+
const value = amount.toFixed(decimals);
|
|
447
|
+
return currency === 'USD' ? `$${value}` : `${value} ${escapeInlineText(currency)}`;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Judge verdict counts. Rendered only when the judge stage ran — `judgedIssues`
|
|
451
|
+
* is the marker, since every other counter is legitimately zero on a clean scan
|
|
452
|
+
* and cannot distinguish "judge ran and found nothing" from "judge never ran".
|
|
453
|
+
*/
|
|
454
|
+
function renderJudgeSummary(results) {
|
|
455
|
+
const { summary } = results;
|
|
456
|
+
if (summary.judgedIssues === undefined)
|
|
457
|
+
return null;
|
|
458
|
+
const lines = [];
|
|
459
|
+
lines.push('## Judge Verdicts');
|
|
460
|
+
lines.push('');
|
|
461
|
+
lines.push(`- **Issues judged:** ${summary.judgedIssues}`);
|
|
462
|
+
if (summary.falsePositives !== undefined) {
|
|
463
|
+
lines.push(`- **Judged false positive:** ${summary.falsePositives}`);
|
|
464
|
+
}
|
|
465
|
+
if (summary.uncertainJudgements !== undefined) {
|
|
466
|
+
lines.push(`- **Uncertain:** ${summary.uncertainJudgements}`);
|
|
467
|
+
}
|
|
468
|
+
if (summary.flaggedByCheck !== undefined) {
|
|
469
|
+
lines.push(`- **Flagged by check:** ${summary.flaggedByCheck}`);
|
|
470
|
+
}
|
|
471
|
+
if (summary.flaggedByJudge !== undefined) {
|
|
472
|
+
lines.push(`- **Flagged by judge:** ${summary.flaggedByJudge}`);
|
|
473
|
+
}
|
|
474
|
+
return lines.join('\n');
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Escape characters that would otherwise be interpreted as Markdown formatting
|
|
478
|
+
* when interpolating arbitrary user/CI strings into bullet content. Conservative
|
|
479
|
+
* — only escapes the syntactic characters that change rendering: `\`, `*`, `_`,
|
|
480
|
+
* `` ` ``, `<`, `[`, `]`, `|`. Newlines collapsed to spaces (bullets are
|
|
481
|
+
* single-line). Keep this scoped to the CI-metadata path where keys/values come
|
|
482
|
+
* from arbitrary `Record<string, unknown>` input.
|
|
483
|
+
*/
|
|
484
|
+
function escapeInlineText(value) {
|
|
485
|
+
return value
|
|
486
|
+
.replace(/\\/g, '\\\\')
|
|
487
|
+
.replace(/[*_`<[\]|]/g, (m) => `\\${m}`)
|
|
488
|
+
// Collapse CRLF, bare LF, *and* a bare CR to a space — CommonMark/GFM
|
|
489
|
+
// treats a lone `\r` as a line ending too (see escapeMarkdownText's
|
|
490
|
+
// identical fix), and an uncollapsed bare CR here would let a renderer
|
|
491
|
+
// split this "single-line" bullet into two lines, letting a leading
|
|
492
|
+
// block marker on the second line escape the bullet.
|
|
493
|
+
.replace(/\r\n?|\n/g, ' ');
|
|
494
|
+
}
|
|
495
|
+
/** Human-readable labels for CIMetadata fields, in display order. */
|
|
496
|
+
const CI_METADATA_LABELS = [
|
|
497
|
+
['jobUrl', 'Job URL'],
|
|
498
|
+
['branch', 'Ref'],
|
|
499
|
+
['pipelineSource', 'Trigger'],
|
|
500
|
+
['jobStartedAt', 'Started'],
|
|
501
|
+
];
|
|
502
|
+
/**
|
|
503
|
+
* Renders `metadata.ciMetadata` as a labelled bullet list.
|
|
504
|
+
*
|
|
505
|
+
* This was originally written when `ScanResults.metadata` was an untyped
|
|
506
|
+
* `Record<string, unknown>` and iterated its top-level keys. #260 replaced that
|
|
507
|
+
* with the closed `ScanMetadata` type, whose members (`ciMetadata`, `cost`) are
|
|
508
|
+
* nested objects — so the generic iteration would have emitted a JSON blob per
|
|
509
|
+
* key, and would also have folded `cost` under a heading titled "CI Metadata".
|
|
510
|
+
*
|
|
511
|
+
* Values are still escaped: they originate from CI environment variables, which
|
|
512
|
+
* are attacker-influenceable on forked-PR builds.
|
|
513
|
+
*/
|
|
514
|
+
function renderCIMetadata(results) {
|
|
515
|
+
const ci = results.metadata?.ciMetadata;
|
|
516
|
+
if (!ci)
|
|
517
|
+
return null;
|
|
518
|
+
const lines = [];
|
|
519
|
+
for (const [key, label] of CI_METADATA_LABELS) {
|
|
520
|
+
const value = ci[key];
|
|
521
|
+
if (value == null || value === '')
|
|
522
|
+
continue;
|
|
523
|
+
lines.push(`- **${label}:** ${escapeInlineText(value)}`);
|
|
524
|
+
}
|
|
525
|
+
// Every field is optional, so a present-but-empty object yields no rows —
|
|
526
|
+
// emit nothing rather than a bare heading.
|
|
527
|
+
if (lines.length === 0)
|
|
528
|
+
return null;
|
|
529
|
+
return ['## CI Metadata', '', ...lines].join('\n');
|
|
530
|
+
}
|
|
531
|
+
export class MarkdownFormatter {
|
|
532
|
+
id = 'markdown';
|
|
533
|
+
fileExtension = '.md';
|
|
534
|
+
format(results) {
|
|
535
|
+
const sections = [
|
|
536
|
+
renderHeader(results),
|
|
537
|
+
renderExecutiveSummary(results),
|
|
538
|
+
renderSummaryTable(results),
|
|
539
|
+
renderDetailedFindings(results),
|
|
540
|
+
];
|
|
541
|
+
const flagged = renderFlaggedItems(results);
|
|
542
|
+
if (flagged)
|
|
543
|
+
sections.push(flagged);
|
|
544
|
+
const errors = renderErrors(results);
|
|
545
|
+
if (errors)
|
|
546
|
+
sections.push(errors);
|
|
547
|
+
const judge = renderJudgeSummary(results);
|
|
548
|
+
if (judge)
|
|
549
|
+
sections.push(judge);
|
|
550
|
+
sections.push(renderStatistics(results));
|
|
551
|
+
const ci = renderCIMetadata(results);
|
|
552
|
+
if (ci)
|
|
553
|
+
sections.push(ci);
|
|
554
|
+
return sections.join('\n\n') + '\n';
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
//# sourceMappingURL=markdown-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-formatter.js","sourceRoot":"","sources":["../../src/formatters/markdown-formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,13 @@ export declare class SarifFormatter implements OutputFormatter {
|
|
|
11
11
|
readonly id = "sarif";
|
|
12
12
|
readonly fileExtension = ".sarif";
|
|
13
13
|
format(results: ScanResults): string;
|
|
14
|
+
/**
|
|
15
|
+
* Map CI/CD metadata (spec E.4) to a single SARIF invocation entry. The
|
|
16
|
+
* `properties` bag is the conventional location for non-standard run
|
|
17
|
+
* context in SARIF; we use stable, namespaced keys (`aghast.<field>`) so
|
|
18
|
+
* downstream consumers can rely on the shape.
|
|
19
|
+
*/
|
|
20
|
+
private buildInvocations;
|
|
14
21
|
private buildRules;
|
|
15
22
|
private buildResults;
|
|
16
23
|
private buildValidationResults;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sarif-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/sarif-formatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"sarif-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/sarif-formatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAA2E,MAAM,aAAa,CAAC;AACxH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAY7F;AAqGD,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,EAAE,WAAW;IACtB,QAAQ,CAAC,aAAa,YAAY;IAElC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAgCpC;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,YAAY;IAqEpB,OAAO,CAAC,sBAAsB;IAoC9B,OAAO,CAAC,aAAa;CAiBtB"}
|