@owasp-aghast/aghast 0.8.3 → 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 (113) hide show
  1. package/config/pricing.json +39 -9
  2. package/dist/build-config.d.ts.map +1 -1
  3. package/dist/build-config.js +101 -2
  4. package/dist/build-config.js.map +1 -1
  5. package/dist/check-library.d.ts +25 -0
  6. package/dist/check-library.d.ts.map +1 -1
  7. package/dist/check-library.js +172 -1
  8. package/dist/check-library.js.map +1 -1
  9. package/dist/ci-metadata.d.ts +42 -0
  10. package/dist/ci-metadata.d.ts.map +1 -0
  11. package/dist/ci-metadata.js +131 -0
  12. package/dist/ci-metadata.js.map +1 -0
  13. package/dist/claude-code-provider.d.ts +7 -0
  14. package/dist/claude-code-provider.d.ts.map +1 -1
  15. package/dist/claude-code-provider.js +65 -1
  16. package/dist/claude-code-provider.js.map +1 -1
  17. package/dist/cli.js +4 -1
  18. package/dist/cli.js.map +1 -1
  19. package/dist/concurrency.d.ts +18 -0
  20. package/dist/concurrency.d.ts.map +1 -0
  21. package/dist/concurrency.js +39 -0
  22. package/dist/concurrency.js.map +1 -0
  23. package/dist/cost-tracker.d.ts +45 -0
  24. package/dist/cost-tracker.d.ts.map +1 -0
  25. package/dist/cost-tracker.js +56 -0
  26. package/dist/cost-tracker.js.map +1 -0
  27. package/dist/discoveries/glob-discovery.d.ts +21 -0
  28. package/dist/discoveries/glob-discovery.d.ts.map +1 -0
  29. package/dist/discoveries/glob-discovery.js +215 -0
  30. package/dist/discoveries/glob-discovery.js.map +1 -0
  31. package/dist/discoveries/script-discovery.d.ts +117 -0
  32. package/dist/discoveries/script-discovery.d.ts.map +1 -0
  33. package/dist/discoveries/script-discovery.js +593 -0
  34. package/dist/discoveries/script-discovery.js.map +1 -0
  35. package/dist/docs-url.d.ts +14 -0
  36. package/dist/docs-url.d.ts.map +1 -0
  37. package/dist/docs-url.js +17 -0
  38. package/dist/docs-url.js.map +1 -0
  39. package/dist/error-codes.d.ts +12 -1
  40. package/dist/error-codes.d.ts.map +1 -1
  41. package/dist/error-codes.js +16 -2
  42. package/dist/error-codes.js.map +1 -1
  43. package/dist/formatters/csv-formatter.d.ts +45 -0
  44. package/dist/formatters/csv-formatter.d.ts.map +1 -0
  45. package/dist/formatters/csv-formatter.js +176 -0
  46. package/dist/formatters/csv-formatter.js.map +1 -0
  47. package/dist/formatters/html-formatter.d.ts +39 -0
  48. package/dist/formatters/html-formatter.d.ts.map +1 -0
  49. package/dist/formatters/html-formatter.js +432 -0
  50. package/dist/formatters/html-formatter.js.map +1 -0
  51. package/dist/formatters/index.d.ts.map +1 -1
  52. package/dist/formatters/index.js +6 -0
  53. package/dist/formatters/index.js.map +1 -1
  54. package/dist/formatters/markdown-formatter.d.ts +61 -0
  55. package/dist/formatters/markdown-formatter.d.ts.map +1 -0
  56. package/dist/formatters/markdown-formatter.js +557 -0
  57. package/dist/formatters/markdown-formatter.js.map +1 -0
  58. package/dist/formatters/sarif-formatter.d.ts +7 -0
  59. package/dist/formatters/sarif-formatter.d.ts.map +1 -1
  60. package/dist/formatters/sarif-formatter.js +80 -0
  61. package/dist/formatters/sarif-formatter.js.map +1 -1
  62. package/dist/formatters/types.d.ts +24 -0
  63. package/dist/formatters/types.d.ts.map +1 -1
  64. package/dist/index.d.ts +4 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +365 -10
  67. package/dist/index.js.map +1 -1
  68. package/dist/issue-file-writer.d.ts +21 -0
  69. package/dist/issue-file-writer.d.ts.map +1 -0
  70. package/dist/issue-file-writer.js +307 -0
  71. package/dist/issue-file-writer.js.map +1 -0
  72. package/dist/judge.d.ts +62 -0
  73. package/dist/judge.d.ts.map +1 -0
  74. package/dist/judge.js +305 -0
  75. package/dist/judge.js.map +1 -0
  76. package/dist/mock-agent-provider.d.ts +3 -0
  77. package/dist/mock-agent-provider.d.ts.map +1 -1
  78. package/dist/mock-agent-provider.js +13 -0
  79. package/dist/mock-agent-provider.js.map +1 -1
  80. package/dist/new-check.d.ts.map +1 -1
  81. package/dist/new-check.js +334 -22
  82. package/dist/new-check.js.map +1 -1
  83. package/dist/opencode-provider.d.ts.map +1 -1
  84. package/dist/opencode-provider.js +33 -0
  85. package/dist/opencode-provider.js.map +1 -1
  86. package/dist/repo-scan.d.ts +80 -0
  87. package/dist/repo-scan.d.ts.map +1 -0
  88. package/dist/repo-scan.js +250 -0
  89. package/dist/repo-scan.js.map +1 -0
  90. package/dist/result-handlers/pr-comment-handler.d.ts +136 -0
  91. package/dist/result-handlers/pr-comment-handler.d.ts.map +1 -0
  92. package/dist/result-handlers/pr-comment-handler.js +381 -0
  93. package/dist/result-handlers/pr-comment-handler.js.map +1 -0
  94. package/dist/retry.d.ts +128 -0
  95. package/dist/retry.d.ts.map +1 -0
  96. package/dist/retry.js +261 -0
  97. package/dist/retry.js.map +1 -0
  98. package/dist/runtime-config.d.ts.map +1 -1
  99. package/dist/runtime-config.js +62 -0
  100. package/dist/runtime-config.js.map +1 -1
  101. package/dist/scan-runner.d.ts +31 -22
  102. package/dist/scan-runner.d.ts.map +1 -1
  103. package/dist/scan-runner.js +145 -100
  104. package/dist/scan-runner.js.map +1 -1
  105. package/dist/semgrep-runner.js +6 -4
  106. package/dist/semgrep-runner.js.map +1 -1
  107. package/dist/stats.d.ts.map +1 -1
  108. package/dist/stats.js +4 -1
  109. package/dist/stats.js.map +1 -1
  110. package/dist/types.d.ts +149 -2
  111. package/dist/types.d.ts.map +1 -1
  112. package/dist/types.js.map +1 -1
  113. 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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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * CSV output formatter — one row per SecurityIssue (plus a row per ERROR check)
3
+ * for spreadsheet analysis (Excel, Google Sheets, etc.).
4
+ *
5
+ * Output contract:
6
+ * - Encoding: UTF-8, no BOM. Excel-on-Windows may render non-ASCII bytes as
7
+ * mojibake when a CSV is opened directly without an encoding hint; consumers
8
+ * that need Excel auto-detection should use the JSON or SARIF output instead,
9
+ * or import the CSV via Excel's "From Text/CSV" wizard which lets you pick
10
+ * UTF-8 explicitly.
11
+ * - Line terminator: CRLF (RFC 4180). Final row is also CRLF-terminated.
12
+ * - Quoting: RFC 4180 — fields containing `,`, `"`, CR, or LF are wrapped in
13
+ * double quotes; embedded `"` is doubled.
14
+ * - Description: flattened to a single line (CR/LF/CRLF → single space) and
15
+ * truncated to {@link DESCRIPTION_MAX_LENGTH} chars with a U+2026 ellipsis.
16
+ * - The structured `dataFlow` taint trace on `SecurityIssue` is intentionally
17
+ * omitted — flat per-issue rows can't represent a list well; SARIF/JSON
18
+ * output keeps the full trace.
19
+ */
20
+ import type { ScanResults } from '../types.js';
21
+ import type { OutputFormatter } from './types.js';
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
+ */
34
+ export declare function escapeCsvField(value: string | number | undefined): string;
35
+ /**
36
+ * Truncates a description to fit within the CSV column and replaces newlines
37
+ * with spaces so each issue stays on a single row.
38
+ */
39
+ export declare function normalizeDescription(description: string): string;
40
+ export declare class CsvFormatter implements OutputFormatter {
41
+ readonly id = "csv";
42
+ readonly fileExtension = ".csv";
43
+ format(results: ScanResults): string;
44
+ }
45
+ //# sourceMappingURL=csv-formatter.d.ts.map
@@ -0,0 +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;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"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * CSV output formatter — one row per SecurityIssue (plus a row per ERROR check)
3
+ * for spreadsheet analysis (Excel, Google Sheets, etc.).
4
+ *
5
+ * Output contract:
6
+ * - Encoding: UTF-8, no BOM. Excel-on-Windows may render non-ASCII bytes as
7
+ * mojibake when a CSV is opened directly without an encoding hint; consumers
8
+ * that need Excel auto-detection should use the JSON or SARIF output instead,
9
+ * or import the CSV via Excel's "From Text/CSV" wizard which lets you pick
10
+ * UTF-8 explicitly.
11
+ * - Line terminator: CRLF (RFC 4180). Final row is also CRLF-terminated.
12
+ * - Quoting: RFC 4180 — fields containing `,`, `"`, CR, or LF are wrapped in
13
+ * double quotes; embedded `"` is doubled.
14
+ * - Description: flattened to a single line (CR/LF/CRLF → single space) and
15
+ * truncated to {@link DESCRIPTION_MAX_LENGTH} chars with a U+2026 ellipsis.
16
+ * - The structured `dataFlow` taint trace on `SecurityIssue` is intentionally
17
+ * omitted — flat per-issue rows can't represent a list well; SARIF/JSON
18
+ * output keeps the full trace.
19
+ */
20
+ /** Maximum length of the description field in CSV output (longer values are truncated with an ellipsis). */
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
+ */
41
+ const CSV_HEADERS = [
42
+ 'checkId',
43
+ 'checkName',
44
+ 'status',
45
+ 'file',
46
+ 'startLine',
47
+ 'endLine',
48
+ 'severity',
49
+ 'confidence',
50
+ 'description',
51
+ 'recommendation',
52
+ 'judgeVerdict',
53
+ 'judgeConfidence',
54
+ 'judgeRationale',
55
+ ];
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
+ */
87
+ export function escapeCsvField(value) {
88
+ if (value === undefined || value === null)
89
+ return '';
90
+ const str = typeof value === 'string' ? neutralizeFormula(value) : String(value);
91
+ // Wrap in quotes if it contains a comma, quote, CR, or LF.
92
+ if (/[",\r\n]/.test(str)) {
93
+ return `"${str.replace(/"/g, '""')}"`;
94
+ }
95
+ return str;
96
+ }
97
+ /**
98
+ * Truncates a description to fit within the CSV column and replaces newlines
99
+ * with spaces so each issue stays on a single row.
100
+ */
101
+ export function normalizeDescription(description) {
102
+ // Replace any sequence of CR/LF with a single space so the cell stays on one line
103
+ // (CSV viewers do support multi-line cells via quoting, but flattening keeps spreadsheets readable).
104
+ const flattened = description.replace(/\r\n|\r|\n/g, ' ').replace(/\s+/g, ' ').trim();
105
+ if (flattened.length <= DESCRIPTION_MAX_LENGTH)
106
+ return flattened;
107
+ return flattened.slice(0, DESCRIPTION_MAX_LENGTH - 1) + '…'; // ellipsis
108
+ }
109
+ function statusForIssue(issue, checkStatusByCheckId) {
110
+ // Fall back to 'UNKNOWN' (not 'FAIL') for orphaned issues so a row in the
111
+ // spreadsheet doesn't claim a check status that wasn't actually reported.
112
+ return checkStatusByCheckId.get(issue.checkId) ?? 'UNKNOWN';
113
+ }
114
+ function issueRow(issue, checkStatus) {
115
+ return [
116
+ escapeCsvField(issue.checkId),
117
+ escapeCsvField(issue.checkName),
118
+ escapeCsvField(checkStatus),
119
+ escapeCsvField(issue.file),
120
+ escapeCsvField(issue.startLine),
121
+ escapeCsvField(issue.endLine),
122
+ escapeCsvField(issue.severity),
123
+ escapeCsvField(issue.confidence),
124
+ escapeCsvField(normalizeDescription(issue.description)),
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),
133
+ ].join(',');
134
+ }
135
+ function errorCheckRow(check) {
136
+ // Surface execution errors so they show up alongside issues in spreadsheets.
137
+ // No file/line/severity/confidence/recommendation — just the error in the description column.
138
+ const description = normalizeDescription(check.error ? `Check execution error: ${check.error}` : 'Check execution error');
139
+ return [
140
+ escapeCsvField(check.checkId),
141
+ escapeCsvField(check.checkName),
142
+ escapeCsvField(check.status),
143
+ '', // file
144
+ '', // startLine
145
+ '', // endLine
146
+ '', // severity
147
+ '', // confidence
148
+ escapeCsvField(description),
149
+ '', // recommendation
150
+ '', // judgeVerdict — an ERROR check produced no issue to judge
151
+ '', // judgeConfidence
152
+ '', // judgeRationale
153
+ ].join(',');
154
+ }
155
+ export class CsvFormatter {
156
+ id = 'csv';
157
+ fileExtension = '.csv';
158
+ format(results) {
159
+ const checkStatusByCheckId = new Map();
160
+ for (const check of results.checks) {
161
+ checkStatusByCheckId.set(check.checkId, check.status);
162
+ }
163
+ const lines = [CSV_HEADERS.join(',')];
164
+ for (const issue of results.issues) {
165
+ lines.push(issueRow(issue, statusForIssue(issue, checkStatusByCheckId)));
166
+ }
167
+ for (const check of results.checks) {
168
+ if (check.status === 'ERROR') {
169
+ lines.push(errorCheckRow(check));
170
+ }
171
+ }
172
+ // RFC 4180 specifies CRLF line endings.
173
+ return lines.join('\r\n') + '\r\n';
174
+ }
175
+ }
176
+ //# sourceMappingURL=csv-formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv-formatter.js","sourceRoot":"","sources":["../../src/formatters/csv-formatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * HTML output formatter — self-contained interactive report.
3
+ *
4
+ * Emits a single .html file with inline CSS + JS. Includes:
5
+ * - Header with title, scan timestamp, repository info
6
+ * - Summary statistics (totals + per-status counters)
7
+ * - Filterable, severity-badged issues table
8
+ * - Expandable per-check sections with optional code snippets
9
+ * - The full `ScanResults` embedded as a JSON island for client-side filtering
10
+ *
11
+ * All user-controlled strings are HTML-escaped via `escapeHtml`. The embedded
12
+ * JSON has `</` sequences neutralised so an attacker-controlled string cannot
13
+ * break out of the `<script type="application/json">` tag.
14
+ */
15
+ import type { ScanResults } from '../types.js';
16
+ import type { OutputFormatter } from './types.js';
17
+ /** Escapes the five HTML special characters. */
18
+ export declare function escapeHtml(value: unknown): string;
19
+ /**
20
+ * Embeds JSON inside a `<script type="application/json">` block safely.
21
+ *
22
+ * Two patterns matter for HTML's script-data tokenizer:
23
+ * 1. `</` — replaced with `<\/` so a stray `</script>` cannot terminate the
24
+ * script element early. `\/` is valid JSON for `/`, so JSON.parse
25
+ * round-trips faithfully.
26
+ * 2. `<!--` — the script-data tokenizer enters a "script data escaped"
27
+ * state on `<!--`, in which a nested `<script>...</script>` pair can
28
+ * terminate the outer element ahead of the literal closing tag we control.
29
+ * Encoding `<` as the Unicode escape `<` is unambiguous JSON
30
+ * (parses back to `<`) and prevents the tokenizer from ever entering the
31
+ * escaped state.
32
+ */
33
+ export declare function escapeJsonForScriptTag(json: string): string;
34
+ export declare class HtmlFormatter implements OutputFormatter {
35
+ readonly id = "html";
36
+ readonly fileExtension = ".html";
37
+ format(results: ScanResults): string;
38
+ }
39
+ //# sourceMappingURL=html-formatter.d.ts.map
@@ -0,0 +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,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"}