@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
package/dist/error-codes.d.ts
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* E4xxx — Repository/target validation
|
|
9
9
|
* E5xxx — Semgrep / Opengrep
|
|
10
10
|
* E6xxx — OpenAnt
|
|
11
|
-
*
|
|
11
|
+
* E70xx — Budget / cost controls
|
|
12
|
+
* E71xx — Script discovery
|
|
13
|
+
* E72xx — Result handlers (PR comments, issue trackers, notifications)
|
|
14
|
+
* E8xxx — Judge stage
|
|
12
15
|
* E9xxx — Internal/fatal
|
|
13
16
|
*/
|
|
14
17
|
export interface ErrorCode {
|
|
@@ -34,6 +37,14 @@ export declare const ERROR_CODES: {
|
|
|
34
37
|
readonly E6001: ErrorCode;
|
|
35
38
|
readonly E6002: ErrorCode;
|
|
36
39
|
readonly E7001: ErrorCode;
|
|
40
|
+
readonly E7101: ErrorCode;
|
|
41
|
+
readonly E7102: ErrorCode;
|
|
42
|
+
readonly E7103: ErrorCode;
|
|
43
|
+
readonly E7104: ErrorCode;
|
|
44
|
+
readonly E7105: ErrorCode;
|
|
45
|
+
readonly E7106: ErrorCode;
|
|
46
|
+
readonly E7201: ErrorCode;
|
|
47
|
+
readonly E8001: ErrorCode;
|
|
37
48
|
readonly E9001: ErrorCode;
|
|
38
49
|
};
|
|
39
50
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDd,CAAC;AAEX;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAWzE"}
|
package/dist/error-codes.js
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* E4xxx — Repository/target validation
|
|
9
9
|
* E5xxx — Semgrep / Opengrep
|
|
10
10
|
* E6xxx — OpenAnt
|
|
11
|
-
*
|
|
11
|
+
* E70xx — Budget / cost controls
|
|
12
|
+
* E71xx — Script discovery
|
|
13
|
+
* E72xx — Result handlers (PR comments, issue trackers, notifications)
|
|
14
|
+
* E8xxx — Judge stage
|
|
12
15
|
* E9xxx — Internal/fatal
|
|
13
16
|
*/
|
|
14
17
|
function ec(code, label) {
|
|
@@ -42,8 +45,19 @@ export const ERROR_CODES = {
|
|
|
42
45
|
// E6xxx — OpenAnt
|
|
43
46
|
E6001: ec('E6001', 'OpenAnt not installed'),
|
|
44
47
|
E6002: ec('E6002', 'OpenAnt execution failed'),
|
|
45
|
-
//
|
|
48
|
+
// E70xx — Budget / cost controls
|
|
46
49
|
E7001: ec('E7001', 'Budget limit exceeded'),
|
|
50
|
+
// E71xx — Script discovery
|
|
51
|
+
E7101: ec('E7101', 'Script discovery timeout'),
|
|
52
|
+
E7102: ec('E7102', 'Script discovery non-zero exit'),
|
|
53
|
+
E7103: ec('E7103', 'Script discovery stdout overflow'),
|
|
54
|
+
E7104: ec('E7104', 'Script discovery spawn/IO failure'),
|
|
55
|
+
E7105: ec('E7105', 'Script discovery output parse failure'),
|
|
56
|
+
E7106: ec('E7106', 'Script discovery unsupported scriptType for platform'),
|
|
57
|
+
// E72xx — Result handlers
|
|
58
|
+
E7201: ec('E7201', 'PR comment posting failed'),
|
|
59
|
+
// E8xxx — Judge stage
|
|
60
|
+
E8001: ec('E8001', 'Judge mock response file not found'),
|
|
47
61
|
// E9xxx — Internal
|
|
48
62
|
E9001: ec('E9001', 'Fatal internal error'),
|
|
49
63
|
};
|
package/dist/error-codes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,18 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type { ScanResults } from '../types.js';
|
|
21
21
|
import type { OutputFormatter } from './types.js';
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Escapes a single CSV field. Two independent defences:
|
|
24
|
+
* 1. Spreadsheet formula injection — {@link neutralizeFormula} (see OWASP).
|
|
25
|
+
* Only applied to `string` values: the formula-trigger set includes `-`,
|
|
26
|
+
* and genuinely numeric columns (`startLine`, `endLine`,
|
|
27
|
+
* `judge.confidence`) can legitimately start with `-` (or, in principle,
|
|
28
|
+
* be produced with other trigger prefixes) — those are never
|
|
29
|
+
* attacker-controlled free text, so quoting them as text would corrupt
|
|
30
|
+
* the number for no security benefit.
|
|
31
|
+
* 2. CSV structure — RFC 4180 quoting: fields containing `,`, `"`, CR or LF
|
|
32
|
+
* are wrapped in double quotes with embedded `"` doubled.
|
|
33
|
+
*/
|
|
23
34
|
export declare function escapeCsvField(value: string | number | undefined): string;
|
|
24
35
|
/**
|
|
25
36
|
* Truncates a description to fit within the CSV column and replaces newlines
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csv-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/csv-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAwC,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"csv-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/csv-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAwC,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AA6DlD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAQzE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAMhE;AAmDD,qBAAa,YAAa,YAAW,eAAe;IAClD,QAAQ,CAAC,EAAE,SAAS;IACpB,QAAQ,CAAC,aAAa,UAAU;IAEhC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAqBrC"}
|
|
@@ -19,6 +19,25 @@
|
|
|
19
19
|
*/
|
|
20
20
|
/** Maximum length of the description field in CSV output (longer values are truncated with an ellipsis). */
|
|
21
21
|
const DESCRIPTION_MAX_LENGTH = 500;
|
|
22
|
+
/**
|
|
23
|
+
* Judge columns are appended at the end and are ALWAYS present, even when the
|
|
24
|
+
* judge did not run (in which case they are empty).
|
|
25
|
+
*
|
|
26
|
+
* Two deliberate choices, both different from the HTML formatter:
|
|
27
|
+
*
|
|
28
|
+
* - Appended, not inserted: a consumer reading by column index keeps working
|
|
29
|
+
* for every column it already knew about.
|
|
30
|
+
* - Unconditional, not "only when the judge ran": CSV is the format most
|
|
31
|
+
* likely to be machine-parsed, and a header row that changes shape
|
|
32
|
+
* depending on runtime configuration is far more hostile to a script than
|
|
33
|
+
* a couple of empty columns. HTML can afford to hide an empty column
|
|
34
|
+
* because a human reads it; a parser cannot.
|
|
35
|
+
*
|
|
36
|
+
* Scan-level cost is deliberately NOT a column. It is a single value for the
|
|
37
|
+
* whole run, so repeating it on every row would invite summing it — yielding
|
|
38
|
+
* cost × issue-count, silently and wrongly. It stays in the JSON, Markdown and
|
|
39
|
+
* HTML reports, where it can be shown once.
|
|
40
|
+
*/
|
|
22
41
|
const CSV_HEADERS = [
|
|
23
42
|
'checkId',
|
|
24
43
|
'checkName',
|
|
@@ -30,12 +49,45 @@ const CSV_HEADERS = [
|
|
|
30
49
|
'confidence',
|
|
31
50
|
'description',
|
|
32
51
|
'recommendation',
|
|
52
|
+
'judgeVerdict',
|
|
53
|
+
'judgeConfidence',
|
|
54
|
+
'judgeRationale',
|
|
33
55
|
];
|
|
34
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Leading characters that make Excel / Google Sheets / LibreOffice interpret a
|
|
58
|
+
* cell as a formula rather than text. A field beginning with one of these — in
|
|
59
|
+
* AI-authored free text (`description`, `recommendation`, judge `rationale`), it
|
|
60
|
+
* is attacker-influenceable via crafted repo content — could execute a formula
|
|
61
|
+
* (e.g. `=HYPERLINK`, `=cmd|...`, `+`/`-`/`@` variants, or DDE) when the CSV is
|
|
62
|
+
* opened. See OWASP "CSV Injection".
|
|
63
|
+
*/
|
|
64
|
+
const FORMULA_TRIGGERS = new Set(['=', '+', '-', '@', '\t', '\r', '\n']);
|
|
65
|
+
/**
|
|
66
|
+
* Neutralises spreadsheet formula injection by prefixing a single quote when the
|
|
67
|
+
* value starts with a formula trigger. The `'` is the conventional OWASP
|
|
68
|
+
* mitigation: spreadsheets treat a leading apostrophe as "this cell is text" and
|
|
69
|
+
* do not display it, so the value reads unchanged while never being evaluated.
|
|
70
|
+
* Applied to the raw value *before* RFC-4180 quoting so both defences compose.
|
|
71
|
+
*/
|
|
72
|
+
function neutralizeFormula(str) {
|
|
73
|
+
return str.length > 0 && FORMULA_TRIGGERS.has(str[0]) ? `'${str}` : str;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Escapes a single CSV field. Two independent defences:
|
|
77
|
+
* 1. Spreadsheet formula injection — {@link neutralizeFormula} (see OWASP).
|
|
78
|
+
* Only applied to `string` values: the formula-trigger set includes `-`,
|
|
79
|
+
* and genuinely numeric columns (`startLine`, `endLine`,
|
|
80
|
+
* `judge.confidence`) can legitimately start with `-` (or, in principle,
|
|
81
|
+
* be produced with other trigger prefixes) — those are never
|
|
82
|
+
* attacker-controlled free text, so quoting them as text would corrupt
|
|
83
|
+
* the number for no security benefit.
|
|
84
|
+
* 2. CSV structure — RFC 4180 quoting: fields containing `,`, `"`, CR or LF
|
|
85
|
+
* are wrapped in double quotes with embedded `"` doubled.
|
|
86
|
+
*/
|
|
35
87
|
export function escapeCsvField(value) {
|
|
36
88
|
if (value === undefined || value === null)
|
|
37
89
|
return '';
|
|
38
|
-
const str = String(value);
|
|
90
|
+
const str = typeof value === 'string' ? neutralizeFormula(value) : String(value);
|
|
39
91
|
// Wrap in quotes if it contains a comma, quote, CR, or LF.
|
|
40
92
|
if (/[",\r\n]/.test(str)) {
|
|
41
93
|
return `"${str.replace(/"/g, '""')}"`;
|
|
@@ -71,6 +123,13 @@ function issueRow(issue, checkStatus) {
|
|
|
71
123
|
escapeCsvField(issue.confidence),
|
|
72
124
|
escapeCsvField(normalizeDescription(issue.description)),
|
|
73
125
|
escapeCsvField(issue.recommendation),
|
|
126
|
+
escapeCsvField(issue.judge?.verdict),
|
|
127
|
+
// Confidence as a plain 0–1 number: spreadsheets can format or threshold it,
|
|
128
|
+
// which a "85%" string would prevent.
|
|
129
|
+
escapeCsvField(issue.judge?.confidence),
|
|
130
|
+
// Model-authored free text — flattened and truncated like description, so a
|
|
131
|
+
// multi-paragraph rationale cannot blow up the row.
|
|
132
|
+
escapeCsvField(issue.judge?.rationale ? normalizeDescription(issue.judge.rationale) : undefined),
|
|
74
133
|
].join(',');
|
|
75
134
|
}
|
|
76
135
|
function errorCheckRow(check) {
|
|
@@ -88,6 +147,9 @@ function errorCheckRow(check) {
|
|
|
88
147
|
'', // confidence
|
|
89
148
|
escapeCsvField(description),
|
|
90
149
|
'', // recommendation
|
|
150
|
+
'', // judgeVerdict — an ERROR check produced no issue to judge
|
|
151
|
+
'', // judgeConfidence
|
|
152
|
+
'', // judgeRationale
|
|
91
153
|
].join(',');
|
|
92
154
|
}
|
|
93
155
|
export class CsvFormatter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csv-formatter.js","sourceRoot":"","sources":["../../src/formatters/csv-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,4GAA4G;AAC5G,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC,MAAM,WAAW,GAAG;IAClB,SAAS;IACT,WAAW;IACX,QAAQ;IACR,MAAM;IACN,WAAW;IACX,SAAS;IACT,UAAU;IACV,YAAY;IACZ,aAAa;IACb,gBAAgB;CACR,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"csv-formatter.js","sourceRoot":"","sources":["../../src/formatters/csv-formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/html-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,WAAW,
|
|
1
|
+
{"version":3,"file":"html-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/html-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,WAAW,EAIZ,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI3D;AA8WD,qBAAa,aAAc,YAAW,eAAe;IACnD,QAAQ,CAAC,EAAE,UAAU;IACrB,QAAQ,CAAC,aAAa,WAAW;IAEjC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAsCrC"}
|
|
@@ -239,7 +239,35 @@ function renderHeader(results) {
|
|
|
239
239
|
</header>
|
|
240
240
|
`;
|
|
241
241
|
}
|
|
242
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Format a cost for display. Sub-cent runs are common with cheap models, and
|
|
244
|
+
* rounding them to "$0.00" reads as "free" rather than "very small".
|
|
245
|
+
*/
|
|
246
|
+
function formatCost(amount, currency) {
|
|
247
|
+
const decimals = amount > 0 && amount < 0.01 ? 4 : 2;
|
|
248
|
+
const value = amount.toFixed(decimals);
|
|
249
|
+
return currency === 'USD' ? `$${value}` : `${value} ${escapeHtml(currency)}`;
|
|
250
|
+
}
|
|
251
|
+
function renderSummary(results, _repo) {
|
|
252
|
+
const { summary } = results;
|
|
253
|
+
const extra = [];
|
|
254
|
+
// Judge tiles appear only when the stage ran. `judgedIssues` is the marker:
|
|
255
|
+
// every other counter is legitimately zero on a clean scan and cannot
|
|
256
|
+
// distinguish "judge ran and found nothing" from "judge never ran".
|
|
257
|
+
if (summary.judgedIssues !== undefined) {
|
|
258
|
+
extra.push(`<div class="stat"><div class="num">${summary.judgedIssues}</div><div class="label">Judged</div></div>`);
|
|
259
|
+
if (summary.falsePositives !== undefined) {
|
|
260
|
+
extra.push(`<div class="stat"><div class="num">${summary.falsePositives}</div><div class="label">False positives</div></div>`);
|
|
261
|
+
}
|
|
262
|
+
if (summary.uncertainJudgements !== undefined) {
|
|
263
|
+
extra.push(`<div class="stat"><div class="num">${summary.uncertainJudgements}</div><div class="label">Uncertain</div></div>`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const cost = results.metadata?.cost;
|
|
267
|
+
if (cost) {
|
|
268
|
+
extra.push(`<div class="stat"><div class="num">${escapeHtml(formatCost(cost.totalCostUsd, cost.currency))}</div>`
|
|
269
|
+
+ `<div class="label">Est. cost</div></div>`);
|
|
270
|
+
}
|
|
243
271
|
return `
|
|
244
272
|
<section class="summary-grid">
|
|
245
273
|
<div class="stat"><div class="num">${summary.totalChecks}</div><div class="label">Checks</div></div>
|
|
@@ -248,6 +276,7 @@ function renderSummary(summary, _repo) {
|
|
|
248
276
|
<div class="stat"><div class="num">${summary.flaggedChecks}</div><div class="label">Flagged</div></div>
|
|
249
277
|
<div class="stat"><div class="num">${summary.errorChecks}</div><div class="label">Errors</div></div>
|
|
250
278
|
<div class="stat"><div class="num">${summary.totalIssues}</div><div class="label">Issues</div></div>
|
|
279
|
+
${extra.join('\n ')}
|
|
251
280
|
</section>
|
|
252
281
|
`;
|
|
253
282
|
}
|
|
@@ -255,10 +284,20 @@ function renderIssuesTable(issues, statusByCheck) {
|
|
|
255
284
|
if (issues.length === 0) {
|
|
256
285
|
return `<section class="card"><h2>Issues</h2><p class="empty">No issues detected.</p></section>`;
|
|
257
286
|
}
|
|
287
|
+
// Only carry a Verdict column when the judge actually annotated something.
|
|
288
|
+
// A permanently empty column on every non-judged scan is worse than none.
|
|
289
|
+
const hasVerdicts = issues.some((i) => i.judge);
|
|
258
290
|
const rows = issues.map((issue) => {
|
|
259
291
|
const sev = issue.severity ?? '';
|
|
260
292
|
const sevCls = severityClass(issue.severity);
|
|
261
293
|
const sevBadge = `<span class="badge ${sevCls}">${escapeHtml(sev || 'unknown')}</span>`;
|
|
294
|
+
const verdictCell = hasVerdicts
|
|
295
|
+
? `<td>${issue.judge
|
|
296
|
+
? `<span class="badge">${escapeHtml(issue.judge.verdict)}</span> `
|
|
297
|
+
+ `<span title="${escapeHtml(issue.judge.rationale ?? '')}">`
|
|
298
|
+
+ `${Math.round(issue.judge.confidence * 100)}%</span>`
|
|
299
|
+
: ''}</td>`
|
|
300
|
+
: '';
|
|
262
301
|
// Fall back to 'UNKNOWN' (not 'FAIL') for orphaned issues so the row's
|
|
263
302
|
// status badge and the data-status filter don't lie when an issue
|
|
264
303
|
// references a checkId that isn't in the checks list.
|
|
@@ -274,6 +313,7 @@ function renderIssuesTable(issues, statusByCheck) {
|
|
|
274
313
|
<td>${sevBadge}</td>
|
|
275
314
|
<td><code>${escapeHtml(issue.file)}</code>:${escapeHtml(issue.startLine)}-${escapeHtml(issue.endLine)}</td>
|
|
276
315
|
<td>${escapeHtml(issue.description)}</td>
|
|
316
|
+
${verdictCell}
|
|
277
317
|
</tr>
|
|
278
318
|
`;
|
|
279
319
|
}).join('');
|
|
@@ -300,7 +340,7 @@ function renderIssuesTable(issues, statusByCheck) {
|
|
|
300
340
|
</div>
|
|
301
341
|
<table id="issues-table" aria-label="Security issues">
|
|
302
342
|
<thead>
|
|
303
|
-
<tr><th>Check ID</th><th>Check</th><th>Status</th><th>Severity</th><th>Location</th><th>Description</th
|
|
343
|
+
<tr><th>Check ID</th><th>Check</th><th>Status</th><th>Severity</th><th>Location</th><th>Description</th>${hasVerdicts ? '<th>Verdict</th>' : ''}</tr>
|
|
304
344
|
</thead>
|
|
305
345
|
<tbody>${rows}</tbody>
|
|
306
346
|
</table>
|
|
@@ -377,7 +417,7 @@ export class HtmlFormatter {
|
|
|
377
417
|
<body>
|
|
378
418
|
<div class="container">
|
|
379
419
|
${renderHeader(results)}
|
|
380
|
-
${renderSummary(results
|
|
420
|
+
${renderSummary(results, results.repository)}
|
|
381
421
|
${renderIssuesTable(results.issues, statusByCheck)}
|
|
382
422
|
${renderCheckDetails(results.checks, issuesByCheck)}
|
|
383
423
|
<footer>Generated by aghast v${escapeHtml(results.version)}</footer>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-formatter.js","sourceRoot":"","sources":["../../src/formatters/html-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"html-formatter.js","sourceRoot":"","sources":["../../src/formatters/html-formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAUlD,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,CAOxD;AAED,yCAAyC;AACzC,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C"}
|
package/dist/formatters/index.js
CHANGED
|
@@ -5,11 +5,13 @@ import { JsonFormatter } from './json-formatter.js';
|
|
|
5
5
|
import { SarifFormatter } from './sarif-formatter.js';
|
|
6
6
|
import { CsvFormatter } from './csv-formatter.js';
|
|
7
7
|
import { HtmlFormatter } from './html-formatter.js';
|
|
8
|
+
import { MarkdownFormatter } from './markdown-formatter.js';
|
|
8
9
|
const formatters = new Map([
|
|
9
10
|
['json', new JsonFormatter()],
|
|
10
11
|
['sarif', new SarifFormatter()],
|
|
11
12
|
['csv', new CsvFormatter()],
|
|
12
13
|
['html', new HtmlFormatter()],
|
|
14
|
+
['markdown', new MarkdownFormatter()],
|
|
13
15
|
]);
|
|
14
16
|
/** Returns the formatter for the given ID, or throws listing available formats. */
|
|
15
17
|
export function getFormatter(id) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAI5D,MAAM,UAAU,GAAG,IAAI,GAAG,CAA0B;IAClD,CAAC,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;IAC7B,CAAC,OAAO,EAAE,IAAI,cAAc,EAAE,CAAC;IAC/B,CAAC,KAAK,EAAE,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;IAC7B,CAAC,UAAU,EAAE,IAAI,iBAAiB,EAAE,CAAC;CACtC,CAAC,CAAC;AAEH,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,0BAA0B,EAAE,yBAAyB,SAAS,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,mBAAmB;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
import type { ScanResults } from '../types.js';
|
|
16
|
+
import type { OutputFormatter } from './types.js';
|
|
17
|
+
/** Resolves the fenced-code-block language tag from a file path. */
|
|
18
|
+
export declare function languageForFile(filePath: string): string;
|
|
19
|
+
/** Wraps code in a fenced block with a language tag, escaping nested fences safely. */
|
|
20
|
+
export declare function fencedCode(code: string, language: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Wraps `value` in a backtick fence long enough to survive any backticks
|
|
23
|
+
* already inside `value`. Per CommonMark, an inline-code span uses a backtick
|
|
24
|
+
* run of length N around a body that contains no run of length N — minimum
|
|
25
|
+
* length 1 (unlike fenced code blocks, which require minimum 3). Pad with a
|
|
26
|
+
* leading/trailing space if the body itself starts or ends with a backtick.
|
|
27
|
+
* Newlines are collapsed to spaces because inline-code spans must be
|
|
28
|
+
* single-line (and table cells must not contain raw newlines).
|
|
29
|
+
*/
|
|
30
|
+
export declare function inlineCode(value: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Escapes AI-authored free text (issue `description` / `recommendation`) for
|
|
33
|
+
* safe rendering as a Markdown *block*.
|
|
34
|
+
*
|
|
35
|
+
* Threat model: these fields come from the LLM's analysis of the scanned
|
|
36
|
+
* repository, whose source can contain attacker-crafted strings. Rendered raw
|
|
37
|
+
* they can inject active HTML that executes when the report is viewed on GitHub,
|
|
38
|
+
* a wiki, or any Markdown viewer permitting inline HTML (`<script>`,
|
|
39
|
+
* `<img onerror=...>`), and can break the report's own structure (table cells,
|
|
40
|
+
* headings, code fences, lists, blockquotes). The HTML formatter already defends
|
|
41
|
+
* the same fields via `escapeHtml`; this is the Markdown-side equivalent.
|
|
42
|
+
*
|
|
43
|
+
* Unlike {@link escapeInlineText}, newlines are *preserved* — these are prose
|
|
44
|
+
* paragraphs, not single-line bullets — so the escaping is applied per line:
|
|
45
|
+
* 1. Inline pass: backslash-escape every character that can open inline
|
|
46
|
+
* formatting or a raw HTML tag (`\` first so we don't re-escape our own
|
|
47
|
+
* escapes). Escaping `<` is what neutralises the inline-HTML vector — per
|
|
48
|
+
* CommonMark/GFM, `\<script>` renders as literal text.
|
|
49
|
+
* 2. Block pass: backslash-escape a leading marker (after optional
|
|
50
|
+
* indentation) that would open a block construct — ATX heading (`#`),
|
|
51
|
+
* list/thematic-break (`-`/`+`), setext underline (`=`), or an ordered-list
|
|
52
|
+
* marker (`1.` / `1)`). Blockquote (`>`) and fences (`` ` ``/`~`) are
|
|
53
|
+
* already handled by the inline pass.
|
|
54
|
+
*/
|
|
55
|
+
export declare function escapeMarkdownText(value: string): string;
|
|
56
|
+
export declare class MarkdownFormatter implements OutputFormatter {
|
|
57
|
+
readonly id = "markdown";
|
|
58
|
+
readonly fileExtension = ".md";
|
|
59
|
+
format(results: ScanResults): string;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=markdown-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AA0ClD,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKxD;AAeD,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAoBhD;AA0BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBxD;AAsWD,qBAAa,iBAAkB,YAAW,eAAe;IACvD,QAAQ,CAAC,EAAE,cAAc;IACzB,QAAQ,CAAC,aAAa,SAAS;IAE/B,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAkBrC"}
|