@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.
Files changed (107) hide show
  1. package/dist/build-config.d.ts.map +1 -1
  2. package/dist/build-config.js +101 -2
  3. package/dist/build-config.js.map +1 -1
  4. package/dist/check-library.d.ts +25 -0
  5. package/dist/check-library.d.ts.map +1 -1
  6. package/dist/check-library.js +165 -0
  7. package/dist/check-library.js.map +1 -1
  8. package/dist/ci-metadata.d.ts +42 -0
  9. package/dist/ci-metadata.d.ts.map +1 -0
  10. package/dist/ci-metadata.js +131 -0
  11. package/dist/ci-metadata.js.map +1 -0
  12. package/dist/cli.js +4 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/concurrency.d.ts +18 -0
  15. package/dist/concurrency.d.ts.map +1 -0
  16. package/dist/concurrency.js +39 -0
  17. package/dist/concurrency.js.map +1 -0
  18. package/dist/cost-tracker.d.ts +45 -0
  19. package/dist/cost-tracker.d.ts.map +1 -0
  20. package/dist/cost-tracker.js +56 -0
  21. package/dist/cost-tracker.js.map +1 -0
  22. package/dist/discoveries/glob-discovery.d.ts +21 -0
  23. package/dist/discoveries/glob-discovery.d.ts.map +1 -0
  24. package/dist/discoveries/glob-discovery.js +215 -0
  25. package/dist/discoveries/glob-discovery.js.map +1 -0
  26. package/dist/discoveries/script-discovery.d.ts +117 -0
  27. package/dist/discoveries/script-discovery.d.ts.map +1 -0
  28. package/dist/discoveries/script-discovery.js +593 -0
  29. package/dist/discoveries/script-discovery.js.map +1 -0
  30. package/dist/docs-url.d.ts +14 -0
  31. package/dist/docs-url.d.ts.map +1 -0
  32. package/dist/docs-url.js +17 -0
  33. package/dist/docs-url.js.map +1 -0
  34. package/dist/error-codes.d.ts +12 -1
  35. package/dist/error-codes.d.ts.map +1 -1
  36. package/dist/error-codes.js +16 -2
  37. package/dist/error-codes.js.map +1 -1
  38. package/dist/formatters/csv-formatter.d.ts +12 -1
  39. package/dist/formatters/csv-formatter.d.ts.map +1 -1
  40. package/dist/formatters/csv-formatter.js +64 -2
  41. package/dist/formatters/csv-formatter.js.map +1 -1
  42. package/dist/formatters/html-formatter.d.ts.map +1 -1
  43. package/dist/formatters/html-formatter.js +43 -3
  44. package/dist/formatters/html-formatter.js.map +1 -1
  45. package/dist/formatters/index.d.ts.map +1 -1
  46. package/dist/formatters/index.js +2 -0
  47. package/dist/formatters/index.js.map +1 -1
  48. package/dist/formatters/markdown-formatter.d.ts +61 -0
  49. package/dist/formatters/markdown-formatter.d.ts.map +1 -0
  50. package/dist/formatters/markdown-formatter.js +557 -0
  51. package/dist/formatters/markdown-formatter.js.map +1 -0
  52. package/dist/formatters/sarif-formatter.d.ts +7 -0
  53. package/dist/formatters/sarif-formatter.d.ts.map +1 -1
  54. package/dist/formatters/sarif-formatter.js +80 -0
  55. package/dist/formatters/sarif-formatter.js.map +1 -1
  56. package/dist/formatters/types.d.ts +24 -0
  57. package/dist/formatters/types.d.ts.map +1 -1
  58. package/dist/index.d.ts +4 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +342 -9
  61. package/dist/index.js.map +1 -1
  62. package/dist/issue-file-writer.d.ts +21 -0
  63. package/dist/issue-file-writer.d.ts.map +1 -0
  64. package/dist/issue-file-writer.js +307 -0
  65. package/dist/issue-file-writer.js.map +1 -0
  66. package/dist/judge.d.ts +62 -0
  67. package/dist/judge.d.ts.map +1 -0
  68. package/dist/judge.js +305 -0
  69. package/dist/judge.js.map +1 -0
  70. package/dist/mock-agent-provider.d.ts +3 -0
  71. package/dist/mock-agent-provider.d.ts.map +1 -1
  72. package/dist/mock-agent-provider.js +13 -0
  73. package/dist/mock-agent-provider.js.map +1 -1
  74. package/dist/new-check.d.ts.map +1 -1
  75. package/dist/new-check.js +322 -13
  76. package/dist/new-check.js.map +1 -1
  77. package/dist/opencode-provider.d.ts.map +1 -1
  78. package/dist/opencode-provider.js +33 -0
  79. package/dist/opencode-provider.js.map +1 -1
  80. package/dist/repo-scan.d.ts +80 -0
  81. package/dist/repo-scan.d.ts.map +1 -0
  82. package/dist/repo-scan.js +250 -0
  83. package/dist/repo-scan.js.map +1 -0
  84. package/dist/result-handlers/pr-comment-handler.d.ts +136 -0
  85. package/dist/result-handlers/pr-comment-handler.d.ts.map +1 -0
  86. package/dist/result-handlers/pr-comment-handler.js +381 -0
  87. package/dist/result-handlers/pr-comment-handler.js.map +1 -0
  88. package/dist/retry.d.ts +128 -0
  89. package/dist/retry.d.ts.map +1 -0
  90. package/dist/retry.js +261 -0
  91. package/dist/retry.js.map +1 -0
  92. package/dist/runtime-config.d.ts.map +1 -1
  93. package/dist/runtime-config.js +62 -0
  94. package/dist/runtime-config.js.map +1 -1
  95. package/dist/scan-runner.d.ts +31 -22
  96. package/dist/scan-runner.d.ts.map +1 -1
  97. package/dist/scan-runner.js +145 -100
  98. package/dist/scan-runner.js.map +1 -1
  99. package/dist/semgrep-runner.js +6 -4
  100. package/dist/semgrep-runner.js.map +1 -1
  101. package/dist/stats.d.ts.map +1 -1
  102. package/dist/stats.js +4 -1
  103. package/dist/stats.js.map +1 -1
  104. package/dist/types.d.ts +149 -2
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/types.js.map +1 -1
  107. package/package.json +1 -1
@@ -8,7 +8,10 @@
8
8
  * E4xxx — Repository/target validation
9
9
  * E5xxx — Semgrep / Opengrep
10
10
  * E6xxx — OpenAnt
11
- * E7xxx — Budget / cost controls
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;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;CAuCd,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"}
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"}
@@ -8,7 +8,10 @@
8
8
  * E4xxx — Repository/target validation
9
9
  * E5xxx — Semgrep / Opengrep
10
10
  * E6xxx — OpenAnt
11
- * E7xxx — Budget / cost controls
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
- // E7xxx — Budget / cost controls
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
  };
@@ -1 +1 @@
1
- {"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,SAAS,EAAE,CAAC,IAAY,EAAE,KAAa;IACrC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,sBAAsB;IACtB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,gCAAgC,CAAC;IACpD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAE5C,wBAAwB;IACxB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,gCAAgC,CAAC;IACpD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,oCAAoC,CAAC;IACxD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAC9C,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,qBAAqB,CAAC;IAEzC,yBAAyB;IACzB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAC5C,yEAAyE;IACzE,wEAAwE;IACxE,qEAAqE;IACrE,oEAAoE;IACpE,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iCAAiC,CAAC;IACrD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAE5C,uCAAuC;IACvC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAE/C,6BAA6B;IAC7B,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC3C,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAE5C,kBAAkB;IAClB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC3C,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAE9C,iCAAiC;IACjC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAE3C,mBAAmB;IACnB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC;CAClC,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,SAAoB,EAAE,OAAe;IAC/D,OAAO,UAAU,SAAS,CAAC,IAAI,MAAM,OAAO,EAAE,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,OAAe;IAC/D,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,kBAAkB,CAAC,gBAAgB,OAAO,mBAAmB,OAAO,EAAE,CAAC,CAAC;IACrF,MAAM,GAAG,GAAG,2DAA2D,KAAK,SAAS,IAAI,aAAa,CAAC;IACvG,OAAO;QACL,uBAAuB,WAAW,CAAC,KAAK,CAAC,IAAI,MAAM,OAAO,EAAE;QAC5D,YAAY,OAAO,EAAE;QACrB,EAAE;QACF,0CAA0C;QAC1C,KAAK,GAAG,EAAE;KACX,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
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
- /** Escapes a single CSV field per RFC 4180. */
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;AAkBlD,+CAA+C;AAC/C,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;AAyCD,qBAAa,YAAa,YAAW,eAAe;IAClD,QAAQ,CAAC,EAAE,SAAS;IACpB,QAAQ,CAAC,aAAa,UAAU;IAEhC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAqBrC"}
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
- /** Escapes a single CSV field per RFC 4180. */
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":"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"}
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,EAKZ,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;AA0TD,qBAAa,aAAc,YAAW,eAAe;IACnD,QAAQ,CAAC,EAAE,UAAU;IACrB,QAAQ,CAAC,aAAa,WAAW;IAEjC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAsCrC"}
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
- function renderSummary(summary, _repo) {
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></tr>
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.summary, results.repository)}
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":"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"}
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;AAMlD,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASlD,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,CAOxD;AAED,yCAAyC;AACzC,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C"}
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"}
@@ -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;AAIpD,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;CAC9B,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"}
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"}