@secureport/core 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -33
- package/dist/coverage.d.ts +21 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +65 -0
- package/dist/coverage.js.map +1 -0
- package/dist/finding.d.ts +89 -0
- package/dist/finding.d.ts.map +1 -0
- package/dist/finding.js +2 -0
- package/dist/finding.js.map +1 -0
- package/dist/fingerprint.d.ts +185 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +247 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/import/burp.d.ts +19 -0
- package/dist/import/burp.d.ts.map +1 -0
- package/dist/import/burp.js +114 -0
- package/dist/import/burp.js.map +1 -0
- package/dist/import/generic.d.ts +90 -0
- package/dist/import/generic.d.ts.map +1 -0
- package/dist/import/generic.js +159 -0
- package/dist/import/generic.js.map +1 -0
- package/dist/import/nessus.d.ts +32 -0
- package/dist/import/nessus.d.ts.map +1 -0
- package/dist/import/nessus.js +125 -0
- package/dist/import/nessus.js.map +1 -0
- package/dist/import/nuclei.d.ts +39 -0
- package/dist/import/nuclei.d.ts.map +1 -0
- package/dist/import/nuclei.js +115 -0
- package/dist/import/nuclei.js.map +1 -0
- package/dist/import/xml.d.ts +47 -0
- package/dist/import/xml.d.ts.map +1 -0
- package/dist/import/xml.js +157 -0
- package/dist/import/xml.js.map +1 -0
- package/dist/import/zap.d.ts +26 -0
- package/dist/import/zap.d.ts.map +1 -0
- package/dist/import/zap.js +119 -0
- package/dist/import/zap.js.map +1 -0
- package/dist/index.d.ts +41 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -2
- package/dist/index.js.map +1 -1
- package/dist/issue.d.ts +190 -11
- package/dist/issue.d.ts.map +1 -1
- package/dist/reconcile.d.ts +115 -10
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/reconcile.js +306 -12
- package/dist/reconcile.js.map +1 -1
- package/dist/report/html.d.ts +21 -0
- package/dist/report/html.d.ts.map +1 -0
- package/dist/report/html.js +324 -0
- package/dist/report/html.js.map +1 -0
- package/dist/report/json.d.ts +81 -0
- package/dist/report/json.d.ts.map +1 -0
- package/dist/report/json.js +47 -0
- package/dist/report/json.js.map +1 -0
- package/dist/report/markdown.d.ts +24 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +304 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/report/model.d.ts +215 -0
- package/dist/report/model.d.ts.map +1 -0
- package/dist/report/model.js +197 -0
- package/dist/report/model.js.map +1 -0
- package/dist/run.d.ts +134 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +2 -0
- package/dist/run.js.map +1 -0
- package/dist/severity.d.ts +191 -0
- package/dist/severity.d.ts.map +1 -0
- package/dist/severity.js +171 -0
- package/dist/severity.js.map +1 -0
- package/dist/snapshot-builder.d.ts +78 -0
- package/dist/snapshot-builder.d.ts.map +1 -0
- package/dist/snapshot-builder.js +172 -0
- package/dist/snapshot-builder.js.map +1 -0
- package/dist/snapshot.d.ts +125 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +2 -0
- package/dist/snapshot.js.map +1 -0
- package/package.json +5 -4
- package/src/coverage.ts +65 -0
- package/src/finding.ts +112 -0
- package/src/fingerprint.ts +315 -0
- package/src/import/burp.ts +126 -0
- package/src/import/generic.ts +258 -0
- package/src/import/nessus.ts +136 -0
- package/src/import/nuclei.ts +173 -0
- package/src/import/xml.ts +187 -0
- package/src/import/zap.ts +161 -0
- package/src/index.ts +75 -2
- package/src/issue.ts +244 -11
- package/src/reconcile.ts +421 -17
- package/src/report/html.ts +449 -0
- package/src/report/json.ts +134 -0
- package/src/report/markdown.ts +435 -0
- package/src/report/model.ts +462 -0
- package/src/run.ts +163 -0
- package/src/severity.ts +250 -0
- package/src/snapshot-builder.ts +225 -0
- package/src/snapshot.ts +146 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { SEVERITY_ORDER } from '../severity.js';
|
|
2
|
+
import { buildReportModel, } from './model.js';
|
|
3
|
+
/** A date, printed the same way everywhere, without a locale to disagree about. */
|
|
4
|
+
export function formatDate(date) {
|
|
5
|
+
return date.toISOString().slice(0, 10);
|
|
6
|
+
}
|
|
7
|
+
/** Escapes the characters that would break out of a Markdown table cell. */
|
|
8
|
+
function cell(value) {
|
|
9
|
+
return value.replace(/\|/gu, '\\|').replace(/\n/gu, ' ');
|
|
10
|
+
}
|
|
11
|
+
/** The change summary every report opens with, per `00-DOMAIN.md` §7. */
|
|
12
|
+
function changeSummary(model) {
|
|
13
|
+
const { run, baseline } = model.snapshot;
|
|
14
|
+
const rows = SEVERITY_ORDER.map((severity) => {
|
|
15
|
+
const cells = [
|
|
16
|
+
severity,
|
|
17
|
+
run.new[severity],
|
|
18
|
+
run.stillOpen[severity],
|
|
19
|
+
run.regressed[severity],
|
|
20
|
+
run.resolved[severity],
|
|
21
|
+
run.ignored[severity],
|
|
22
|
+
];
|
|
23
|
+
return `| ${cells.join(' | ')} |`;
|
|
24
|
+
});
|
|
25
|
+
return [
|
|
26
|
+
'## What changed',
|
|
27
|
+
'',
|
|
28
|
+
baseline === undefined
|
|
29
|
+
? '_First run against this target, so every issue is new._'
|
|
30
|
+
: `_Compared with the run of ${formatDate(baseline.createdAt)}._`,
|
|
31
|
+
'',
|
|
32
|
+
'| Severity | New | Still open | Regressed | Resolved | Suppressed |',
|
|
33
|
+
'| --- | --- | --- | --- | --- | --- |',
|
|
34
|
+
...rows,
|
|
35
|
+
'',
|
|
36
|
+
`**${model.outstandingTotal} outstanding.** Exposure score ${model.exposureScore}.` +
|
|
37
|
+
(model.breached > 0
|
|
38
|
+
? ` **${model.breached} past ${model.breached === 1 ? 'its' : 'their'} remediation deadline.**`
|
|
39
|
+
: ''),
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
/** One issue, in full. The Penetration Test presentation. */
|
|
43
|
+
function issueDetail(entry) {
|
|
44
|
+
const { issue } = entry;
|
|
45
|
+
const lines = [
|
|
46
|
+
`#### ${issue.title}`,
|
|
47
|
+
'',
|
|
48
|
+
`| | |`,
|
|
49
|
+
`| --- | --- |`,
|
|
50
|
+
`| Severity | ${issue.effectiveSeverity}${issue.effectiveSeverity === issue.detectedSeverity
|
|
51
|
+
? ''
|
|
52
|
+
: ` (detected ${issue.detectedSeverity})`} |`,
|
|
53
|
+
`| Status | ${issue.status} · ${entry.change.replace('_', ' ')} |`,
|
|
54
|
+
`| Location | \`${cell(issue.location)}\`${issue.parameter === undefined ? '' : ` (\`${cell(issue.parameter)}\`)`} |`,
|
|
55
|
+
`| First seen | ${formatDate(issue.firstSeen)} (${entry.daysOpen} days) |`,
|
|
56
|
+
`| Remediation | ${issue.slaDueAt === undefined || issue.slaDueAt === null
|
|
57
|
+
? 'no deadline'
|
|
58
|
+
: `${formatDate(issue.slaDueAt)} — ${entry.slaStatus.replace('_', ' ')}`} |`,
|
|
59
|
+
];
|
|
60
|
+
if (issue.cwe !== undefined)
|
|
61
|
+
lines.push(`| Weakness | ${issue.cwe} |`);
|
|
62
|
+
lines.push('');
|
|
63
|
+
const first = entry.findings[0];
|
|
64
|
+
if (first?.description !== undefined)
|
|
65
|
+
lines.push(first.description, '');
|
|
66
|
+
if (first?.recommendation !== undefined) {
|
|
67
|
+
lines.push('**Recommendation.** ' + first.recommendation, '');
|
|
68
|
+
}
|
|
69
|
+
if (entry.findings.length > 0) {
|
|
70
|
+
// The count, not the engine. Which scanner produced a finding is an
|
|
71
|
+
// implementation detail of the assessment, and naming the stack in a
|
|
72
|
+
// customer-facing document gives away more than it explains.
|
|
73
|
+
lines.push(`_Evidence: ${entry.findings.length} finding${entry.findings.length === 1 ? '' : 's'} recorded._`, '');
|
|
74
|
+
const references = [...new Set(entry.findings.flatMap((f) => f.references ?? []))];
|
|
75
|
+
if (references.length > 0) {
|
|
76
|
+
lines.push(...references.map((r) => `- ${r}`), '');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return lines;
|
|
80
|
+
}
|
|
81
|
+
/** One issue, as a table row. The Vulnerability Assessment presentation. */
|
|
82
|
+
function issueRow(entry) {
|
|
83
|
+
const { issue } = entry;
|
|
84
|
+
const location = issue.parameter === undefined ? issue.location : `${issue.location} (${issue.parameter})`;
|
|
85
|
+
return `| ${cell(issue.title)} | ${issue.effectiveSeverity} | \`${cell(location)}\` | ${entry.change.replace('_', ' ')} | ${entry.daysOpen} | ${entry.slaStatus.replace('_', ' ')} |`;
|
|
86
|
+
}
|
|
87
|
+
/** How a verdict is printed. The dashes are an implementation detail. */
|
|
88
|
+
const VERDICT_LABELS = Object.freeze({
|
|
89
|
+
fixed: 'fixed',
|
|
90
|
+
still_present: 'still present',
|
|
91
|
+
returned: 'returned',
|
|
92
|
+
not_retested: 'not retested',
|
|
93
|
+
new: 'new since',
|
|
94
|
+
});
|
|
95
|
+
/** The Retest body: the difference between two runs, and nothing else. */
|
|
96
|
+
function retestBody(model) {
|
|
97
|
+
// `buildReportModel` refuses to build a retest without one.
|
|
98
|
+
const retest = model.retest;
|
|
99
|
+
const { counts } = retest;
|
|
100
|
+
const carried = counts.fixed + counts.still_present + counts.returned + counts.not_retested;
|
|
101
|
+
const lines = [
|
|
102
|
+
'## Retest verdict',
|
|
103
|
+
'',
|
|
104
|
+
`Retested against the run of ${formatDate(retest.baseline.createdAt)}.`,
|
|
105
|
+
'',
|
|
106
|
+
carried === 0
|
|
107
|
+
? 'No issues were carried into this retest.'
|
|
108
|
+
: `Of the ${carried} issue${carried === 1 ? '' : 's'} carried into this retest, ` +
|
|
109
|
+
`**${counts.fixed} ${counts.fixed === 1 ? 'is' : 'are'} confirmed fixed**, ` +
|
|
110
|
+
`${counts.still_present} ${counts.still_present === 1 ? 'is' : 'are'} still present, ` +
|
|
111
|
+
`${counts.returned} returned, and ${counts.not_retested} could not be retested.` +
|
|
112
|
+
(counts.new === 0
|
|
113
|
+
? ''
|
|
114
|
+
: ` A further ${counts.new} ${counts.new === 1 ? 'issue was' : 'issues were'} found for the first time by this run.`),
|
|
115
|
+
'',
|
|
116
|
+
];
|
|
117
|
+
if (retest.fixRate !== null) {
|
|
118
|
+
lines.push(`${Math.round(retest.fixRate * 100)}% of the issues this run could check are fixed.`, '');
|
|
119
|
+
}
|
|
120
|
+
lines.push('| Verdict | Issues |', '| --- | --- |', ...Object.keys(VERDICT_LABELS).map((v) => `| ${VERDICT_LABELS[v]} | ${counts[v]} |`), '');
|
|
121
|
+
// The section that stops this document reporting a coverage gap as
|
|
122
|
+
// remediation. Stated before the issue table, not in a footnote after it.
|
|
123
|
+
if (counts.not_retested > 0) {
|
|
124
|
+
lines.push('## Not retested', '', `${counts.not_retested} issue${counts.not_retested === 1 ? '' : 's'} could not be retested by this run:`, 'the run did not cover where they were found, or has not missed them often enough to', 'call them resolved. **They are not fixed.** An issue nobody looked at is neither fixed', 'nor unfixed, and it is excluded from the percentage above rather than counted either way.', '');
|
|
125
|
+
}
|
|
126
|
+
if (retest.entries.length === 0) {
|
|
127
|
+
lines.push('## Issue by issue', '', '_No issues._', '');
|
|
128
|
+
return lines;
|
|
129
|
+
}
|
|
130
|
+
lines.push('## Issue by issue', '', '| Issue | Severity | Verdict | Location | Open for |', '| --- | --- | --- | --- | --- |', ...retest.entries.map((entry) => {
|
|
131
|
+
const { issue } = entry.issue;
|
|
132
|
+
const location = issue.parameter === undefined ? issue.location : `${issue.location} (${issue.parameter})`;
|
|
133
|
+
return `| ${cell(issue.title)} | ${issue.effectiveSeverity} | ${VERDICT_LABELS[entry.verdict]} | \`${cell(location)}\` | ${entry.issue.daysOpen} days |`;
|
|
134
|
+
}), '');
|
|
135
|
+
return lines;
|
|
136
|
+
}
|
|
137
|
+
/** The suppressed-findings appendix. On by default, never optional. */
|
|
138
|
+
function suppressedAppendix(snapshot) {
|
|
139
|
+
if (snapshot.suppressed.length === 0) {
|
|
140
|
+
return ['## Suppressed findings', '', '_None._'];
|
|
141
|
+
}
|
|
142
|
+
return [
|
|
143
|
+
'## Suppressed findings',
|
|
144
|
+
'',
|
|
145
|
+
'Accepted, out of scope or dismissed. Listed because an accepted risk that',
|
|
146
|
+
'nobody can see is not an accepted risk.',
|
|
147
|
+
'',
|
|
148
|
+
'| Issue | Severity when suppressed | Reason | By | Expires | Justification |',
|
|
149
|
+
'| --- | --- | --- | --- | --- | --- |',
|
|
150
|
+
...snapshot.suppressed.map((s) => `| ${cell(s.issue.title)} | ${s.severityAtIgnore} | ${s.reason.replace('_', ' ')} | ${cell(s.ignoredBy)} | ${s.expiresAt === undefined ? 'never' : formatDate(s.expiresAt)} | ${cell(s.comment)} |`),
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
/** The Executive Summary body: what changed, what it means, no technical detail. */
|
|
154
|
+
function executiveBody(model) {
|
|
155
|
+
const resolvedCount = model.resolved.length;
|
|
156
|
+
const regressed = model.sections
|
|
157
|
+
.flatMap((s) => s.issues)
|
|
158
|
+
.filter((i) => i.change === 'regressed').length;
|
|
159
|
+
const headline = model.outstandingTotal === 0
|
|
160
|
+
? 'Nothing is currently outstanding on this target.'
|
|
161
|
+
: `${model.outstandingTotal} issue${model.outstandingTotal === 1 ? '' : 's'} ${model.outstandingTotal === 1 ? 'is' : 'are'} currently outstanding, of which ${model.outstanding.critical + model.outstanding.high} ` +
|
|
162
|
+
`${model.outstanding.critical + model.outstanding.high === 1 ? 'is' : 'are'} critical or high.`;
|
|
163
|
+
const lines = ['## Where things stand', '', headline, ''];
|
|
164
|
+
if (resolvedCount > 0) {
|
|
165
|
+
lines.push(`${resolvedCount} issue${resolvedCount === 1 ? ' was' : 's were'} resolved since the last run.`, '');
|
|
166
|
+
}
|
|
167
|
+
if (regressed > 0) {
|
|
168
|
+
lines.push(`**${regressed} previously resolved issue${regressed === 1 ? ' has' : 's have'} returned.** ` +
|
|
169
|
+
'A returning issue usually means a fix was reverted or incompletely applied.', '');
|
|
170
|
+
}
|
|
171
|
+
if (model.breached > 0) {
|
|
172
|
+
lines.push(`**${model.breached} ${model.breached === 1 ? 'is' : 'are'} past the remediation deadline** ` +
|
|
173
|
+
'set by the severity policy.', '');
|
|
174
|
+
}
|
|
175
|
+
lines.push('## Outstanding by severity', '', '| Severity | Outstanding |', '| --- | --- |', ...SEVERITY_ORDER.filter((sev) => model.outstanding[sev] > 0).map((sev) => `| ${sev} | ${model.outstanding[sev]} |`), '');
|
|
176
|
+
if (model.outstandingTotal === 0)
|
|
177
|
+
lines.push('_Nothing outstanding._', '');
|
|
178
|
+
// Named, but not explained. An executive summary that reproduces the
|
|
179
|
+
// technical report is not a summary, and the reader who wants detail has the
|
|
180
|
+
// other three.
|
|
181
|
+
const notable = model.sections
|
|
182
|
+
.flatMap((s) => s.issues)
|
|
183
|
+
.filter((i) => ['critical', 'high'].includes(i.issue.effectiveSeverity))
|
|
184
|
+
.slice(0, 10);
|
|
185
|
+
if (notable.length > 0) {
|
|
186
|
+
lines.push('## What needs attention first', '', ...notable.map((entry) => `- **${entry.issue.effectiveSeverity}** — ${entry.issue.title} (open ${entry.daysOpen} days)`), '', '_Full detail, including evidence, is in the accompanying technical report._', '');
|
|
187
|
+
}
|
|
188
|
+
lines.push(`Exposure score ${model.exposureScore}. This is a single number combining how many issues`, 'are open, how severe they are and how long they have been open. It falls as issues are', 'fixed and rises while they are not.', '');
|
|
189
|
+
return lines;
|
|
190
|
+
}
|
|
191
|
+
/** The Attestation Letter body: a formal statement, with its limits stated. */
|
|
192
|
+
function attestationBody(model) {
|
|
193
|
+
const { snapshot } = model;
|
|
194
|
+
const found = snapshot.issues.length + snapshot.suppressed.length;
|
|
195
|
+
return [
|
|
196
|
+
'## Statement',
|
|
197
|
+
'',
|
|
198
|
+
`${model.preparedBy ?? 'Secureport'} carried out security testing of **${snapshot.target.name}**`,
|
|
199
|
+
`(${snapshot.target.url}) on ${formatDate(snapshot.run.createdAt)}.`,
|
|
200
|
+
'',
|
|
201
|
+
model.basis.statement,
|
|
202
|
+
'',
|
|
203
|
+
`The testing identified ${found} issue${found === 1 ? '' : 's'} in total, of which`,
|
|
204
|
+
`${model.outstandingTotal} ${model.outstandingTotal === 1 ? 'remains' : 'remain'} outstanding at the date of this letter:`,
|
|
205
|
+
'',
|
|
206
|
+
'| Severity | Outstanding |',
|
|
207
|
+
'| --- | --- |',
|
|
208
|
+
...SEVERITY_ORDER.map((sev) => `| ${sev} | ${model.outstanding[sev]} |`),
|
|
209
|
+
'',
|
|
210
|
+
// The most important section in the document, and deliberately not last:
|
|
211
|
+
// a reader who stops early must still have read it.
|
|
212
|
+
'## What this letter does not establish',
|
|
213
|
+
'',
|
|
214
|
+
...model.limitations.map((l) => `- ${l}`),
|
|
215
|
+
'',
|
|
216
|
+
'## Scope tested',
|
|
217
|
+
'',
|
|
218
|
+
...snapshot.run.coverage.paths.map((p) => `- \`${cell(p)}\``),
|
|
219
|
+
'',
|
|
220
|
+
];
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Renders a snapshot as Markdown.
|
|
224
|
+
*
|
|
225
|
+
* The Penetration Test report gives every issue in full with its evidence; the
|
|
226
|
+
* Vulnerability Assessment tabulates the same issues; the Executive Summary
|
|
227
|
+
* says what changed and what it means without technical detail; the Attestation
|
|
228
|
+
* Letter states formally that testing was carried out, and states what it does
|
|
229
|
+
* not establish as prominently as what it found. **They are presentations of one
|
|
230
|
+
* snapshot** — any difference in substance would be a bug.
|
|
231
|
+
*
|
|
232
|
+
* Deterministic: the same snapshot and the same `now` produce byte-identical
|
|
233
|
+
* output, which is what lets a report be compared with the copy somebody was
|
|
234
|
+
* sent, and what makes golden-file testing meaningful.
|
|
235
|
+
*
|
|
236
|
+
* @param snapshot - Issue state as of a run.
|
|
237
|
+
* @param options - Which report, attribution, and the render time.
|
|
238
|
+
* @returns The report as Markdown.
|
|
239
|
+
*/
|
|
240
|
+
export function renderMarkdown(snapshot, options) {
|
|
241
|
+
const model = buildReportModel(snapshot, options);
|
|
242
|
+
const { target } = snapshot;
|
|
243
|
+
const lines = [
|
|
244
|
+
`# ${model.title}`,
|
|
245
|
+
'',
|
|
246
|
+
`**${target.name}** — ${target.url}`,
|
|
247
|
+
'',
|
|
248
|
+
`| | |`,
|
|
249
|
+
`| --- | --- |`,
|
|
250
|
+
`| Generated | ${formatDate(model.generatedAt)} |`,
|
|
251
|
+
`| Run | ${snapshot.run.runId} (${snapshot.run.trigger}) |`,
|
|
252
|
+
];
|
|
253
|
+
if (model.preparedFor !== undefined)
|
|
254
|
+
lines.push(`| Prepared for | ${cell(model.preparedFor)} |`);
|
|
255
|
+
if (model.preparedBy !== undefined)
|
|
256
|
+
lines.push(`| Prepared by | ${cell(model.preparedBy)} |`);
|
|
257
|
+
lines.push('');
|
|
258
|
+
// The Attestation Letter carries the basis, the scope and the counts itself,
|
|
259
|
+
// in the order a letter reads. Adding the report furniture on top would state
|
|
260
|
+
// each of them twice, and a formal document that repeats itself is one a
|
|
261
|
+
// reader stops trusting.
|
|
262
|
+
if (model.kind === 'attest') {
|
|
263
|
+
lines.push(...attestationBody(model), ...suppressedAppendix(snapshot), '');
|
|
264
|
+
return lines.join('\n');
|
|
265
|
+
}
|
|
266
|
+
lines.push('## Basis of testing', '', model.basis.statement, '');
|
|
267
|
+
lines.push('## Scope', '', `This report covers only what the run exercised: ${snapshot.run.coverage.paths
|
|
268
|
+
.map((p) => `\`${cell(p)}\``)
|
|
269
|
+
.join(', ')}.`, 'Anything outside that was not tested and is not described here.', '');
|
|
270
|
+
lines.push(...changeSummary(model), '');
|
|
271
|
+
if (model.kind === 'exec') {
|
|
272
|
+
lines.push(...executiveBody(model), ...suppressedAppendix(snapshot), '');
|
|
273
|
+
return lines.join('\n');
|
|
274
|
+
}
|
|
275
|
+
if (model.kind === 'retest') {
|
|
276
|
+
lines.push(...retestBody(model), ...suppressedAppendix(snapshot), '');
|
|
277
|
+
return lines.join('\n');
|
|
278
|
+
}
|
|
279
|
+
if (model.sections.length === 0) {
|
|
280
|
+
lines.push('## Findings', '', '_No issues were found._', '');
|
|
281
|
+
}
|
|
282
|
+
else if (model.kind === 'pen') {
|
|
283
|
+
lines.push('## Findings', '');
|
|
284
|
+
for (const section of model.sections) {
|
|
285
|
+
lines.push(`### ${section.severity} (${section.issues.length})`, '');
|
|
286
|
+
for (const entry of section.issues)
|
|
287
|
+
lines.push(...issueDetail(entry));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
lines.push('## Findings', '', '| Issue | Severity | Location | Change | Days open | Remediation |', '| --- | --- | --- | --- | --- | --- |');
|
|
292
|
+
for (const section of model.sections) {
|
|
293
|
+
for (const entry of section.issues)
|
|
294
|
+
lines.push(issueRow(entry));
|
|
295
|
+
}
|
|
296
|
+
lines.push('');
|
|
297
|
+
}
|
|
298
|
+
if (model.resolved.length > 0) {
|
|
299
|
+
lines.push('## Resolved since the last run', '', `${model.resolved.length} issue${model.resolved.length === 1 ? '' : 's'} no longer detected by a run that covered ${model.resolved.length === 1 ? 'it' : 'them'}.`, '', '| Issue | Severity | Location | Open for |', '| --- | --- | --- | --- |', ...model.resolved.map((entry) => `| ${cell(entry.issue.title)} | ${entry.issue.effectiveSeverity} | \`${cell(entry.issue.location)}\` | ${entry.daysOpen} days |`), '');
|
|
300
|
+
}
|
|
301
|
+
lines.push(...suppressedAppendix(snapshot), '');
|
|
302
|
+
return lines.join('\n');
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { RunSummary } from '../run.js';
|
|
2
|
+
import type { Severity } from '../severity.js';
|
|
3
|
+
import type { Snapshot, SnapshotIssue } from '../snapshot.js';
|
|
4
|
+
/**
|
|
5
|
+
* Which report to render.
|
|
6
|
+
*
|
|
7
|
+
* - `pen` — Penetration Test. Every issue in full, with its evidence.
|
|
8
|
+
* - `vap` — Vulnerability Assessment. The same issues, tabulated.
|
|
9
|
+
* - `exec` — Executive Summary. What changed and what it means, no technical
|
|
10
|
+
* detail, for a reader who will not open the others.
|
|
11
|
+
* - `attest` — Attestation Letter. A formal statement that testing was carried
|
|
12
|
+
* out, with its limitations stated as prominently as its findings.
|
|
13
|
+
* - `retest` — Retest. The difference between two runs: what was fixed, what is
|
|
14
|
+
* still there, and what came back. The only kind that requires a baseline.
|
|
15
|
+
*
|
|
16
|
+
* **They are presentations of one snapshot, not four analyses.** Anything that
|
|
17
|
+
* differs between them is layout or level of detail; a number that differed
|
|
18
|
+
* would be a bug.
|
|
19
|
+
*/
|
|
20
|
+
export type ReportKind = 'pen' | 'vap' | 'exec' | 'attest' | 'retest';
|
|
21
|
+
/** What a caller can say about a report that the snapshot does not know. */
|
|
22
|
+
export interface ReportOptions {
|
|
23
|
+
/** Which report to render. */
|
|
24
|
+
readonly kind: ReportKind;
|
|
25
|
+
/** Overrides the default title. */
|
|
26
|
+
readonly title?: string;
|
|
27
|
+
/** Who prepared it. White-labelling is a branding option, not a report type. */
|
|
28
|
+
readonly preparedBy?: string;
|
|
29
|
+
/** Who it is for. */
|
|
30
|
+
readonly preparedFor?: string;
|
|
31
|
+
/**
|
|
32
|
+
* When it was rendered.
|
|
33
|
+
*
|
|
34
|
+
* An argument, like everywhere else in this package: a report re-rendered
|
|
35
|
+
* from the same snapshot must come out identical, or it cannot be compared
|
|
36
|
+
* with the copy somebody was sent.
|
|
37
|
+
*/
|
|
38
|
+
readonly now: Date;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* How the findings in a report were actually produced.
|
|
42
|
+
*
|
|
43
|
+
* **This exists because of the honesty rule in `00-DOMAIN.md` §7.** That rule
|
|
44
|
+
* is written about the Attestation Letter, but a "Penetration Test" report
|
|
45
|
+
* built entirely from automated scanner output is the same over-claim: it is
|
|
46
|
+
* the fastest way to lose an auditor's trust, and with it the compliance
|
|
47
|
+
* business.
|
|
48
|
+
*
|
|
49
|
+
* So the basis is derived from the data rather than asserted by the template. A
|
|
50
|
+
* report over `scan` runs says automated; one that includes findings a person
|
|
51
|
+
* recorded says so; one over an upload says the results were brought from
|
|
52
|
+
* elsewhere. Nobody has to remember to be honest.
|
|
53
|
+
*
|
|
54
|
+
* It also carries the advice that automated findings **should be verified by a
|
|
55
|
+
* qualified technician before the report is submitted as audit evidence**. That
|
|
56
|
+
* is the practical form of the same rule: a scanner's output is a starting
|
|
57
|
+
* point for an assessment, not the assessment, and saying so protects both the
|
|
58
|
+
* reader and whoever hands them the document.
|
|
59
|
+
*
|
|
60
|
+
* The method is described; **the engines are not named**. Which scanner found
|
|
61
|
+
* something is an implementation detail, and naming the stack in a
|
|
62
|
+
* customer-facing report gives away more than it explains.
|
|
63
|
+
*/
|
|
64
|
+
export interface TestingBasis {
|
|
65
|
+
/** Whether any finding came from a human rather than an engine. */
|
|
66
|
+
readonly includesManual: boolean;
|
|
67
|
+
/** Whether Secureport originated the traffic. */
|
|
68
|
+
readonly automated: boolean;
|
|
69
|
+
/** Whether results were brought from another tool. */
|
|
70
|
+
readonly uploaded: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The engines involved, in the order the run recorded them.
|
|
73
|
+
*
|
|
74
|
+
* **Available, but deliberately not printed.** Which scanner produced a
|
|
75
|
+
* finding is an implementation detail of the assessment, not a fact the
|
|
76
|
+
* reader needs, and naming the stack in a customer-facing document gives
|
|
77
|
+
* away more than it explains. The prose describes the *method*; this field is
|
|
78
|
+
* here for a consumer that has a reason to know.
|
|
79
|
+
*/
|
|
80
|
+
readonly engines: readonly string[];
|
|
81
|
+
/** One sentence, ready to print. */
|
|
82
|
+
readonly statement: string;
|
|
83
|
+
}
|
|
84
|
+
/** A group of issues sharing a severity, most urgent first. */
|
|
85
|
+
export interface ReportSection {
|
|
86
|
+
/** The severity this section covers. */
|
|
87
|
+
readonly severity: Severity;
|
|
88
|
+
/** Its issues, most recently seen first. */
|
|
89
|
+
readonly issues: readonly SnapshotIssue[];
|
|
90
|
+
}
|
|
91
|
+
/** Everything a renderer needs, derived once so no two formats disagree. */
|
|
92
|
+
export interface ReportModel {
|
|
93
|
+
/** Which report this is. */
|
|
94
|
+
readonly kind: ReportKind;
|
|
95
|
+
/** The title as printed. */
|
|
96
|
+
readonly title: string;
|
|
97
|
+
/** The snapshot it was built from. */
|
|
98
|
+
readonly snapshot: Snapshot;
|
|
99
|
+
/** When it was rendered. */
|
|
100
|
+
readonly generatedAt: Date;
|
|
101
|
+
/** Who prepared it, if stated. */
|
|
102
|
+
readonly preparedBy?: string;
|
|
103
|
+
/** Who it is for, if stated. */
|
|
104
|
+
readonly preparedFor?: string;
|
|
105
|
+
/** How the findings were produced. */
|
|
106
|
+
readonly basis: TestingBasis;
|
|
107
|
+
/**
|
|
108
|
+
* Outstanding issues grouped by severity, most urgent first, empties dropped.
|
|
109
|
+
*
|
|
110
|
+
* **Resolved issues are not here.** A fixed issue is not a finding — it is
|
|
111
|
+
* evidence of remediation, and listing it under "Findings" makes a report
|
|
112
|
+
* read as though the work is still outstanding. It has its own section.
|
|
113
|
+
*/
|
|
114
|
+
readonly sections: readonly ReportSection[];
|
|
115
|
+
/**
|
|
116
|
+
* Issues this run resolved, most recently seen first.
|
|
117
|
+
*
|
|
118
|
+
* Kept and shown rather than dropped: "what you fixed" is the story the
|
|
119
|
+
* product exists to tell, and a report that silently omits it throws away its
|
|
120
|
+
* best evidence.
|
|
121
|
+
*/
|
|
122
|
+
readonly resolved: readonly SnapshotIssue[];
|
|
123
|
+
/** Open and regressed issues, by severity. What the reader owes work on. */
|
|
124
|
+
readonly outstanding: Readonly<Record<Severity, number>>;
|
|
125
|
+
/** Total outstanding, so a header does not have to sum a table. */
|
|
126
|
+
readonly outstandingTotal: number;
|
|
127
|
+
/** Exposure at the end of the run. */
|
|
128
|
+
readonly exposureScore: number;
|
|
129
|
+
/** Issues past their remediation deadline. */
|
|
130
|
+
readonly breached: number;
|
|
131
|
+
/**
|
|
132
|
+
* What this report does not establish.
|
|
133
|
+
*
|
|
134
|
+
* **Stated as prominently as the findings, and not optional.** An attestation
|
|
135
|
+
* that lists what was found and stays quiet about what it cannot support is
|
|
136
|
+
* the over-claim `00-DOMAIN.md` §7 warns about — and it is the fastest way to
|
|
137
|
+
* lose an auditor's trust, and with it the compliance business.
|
|
138
|
+
*
|
|
139
|
+
* Derived, so the limitations match the report rather than being boilerplate
|
|
140
|
+
* somebody forgot to update: a report over automated results says so, a
|
|
141
|
+
* partial scope says so, and none of them claims compliance with a standard
|
|
142
|
+
* nothing here assessed.
|
|
143
|
+
*/
|
|
144
|
+
readonly limitations: readonly string[];
|
|
145
|
+
/**
|
|
146
|
+
* What this run established about the issues carried into it.
|
|
147
|
+
*
|
|
148
|
+
* Present whenever the snapshot has a baseline, whatever the kind. Absent on
|
|
149
|
+
* a first run, where there is nothing to compare against.
|
|
150
|
+
*/
|
|
151
|
+
readonly retest?: RetestOutcome;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* What a retest established about one issue.
|
|
155
|
+
*
|
|
156
|
+
* - `fixed` — carried in from the baseline and no longer detected by a run that
|
|
157
|
+
* covered it. The only verdict that is evidence of remediation.
|
|
158
|
+
* - `still_present` — detected again by this run.
|
|
159
|
+
* - `returned` — was resolved and this run found it again.
|
|
160
|
+
* - `not_retested` — **not detected, and not fixed either.** The run did not
|
|
161
|
+
* cover it, or has not missed it often enough to resolve it. A retest that
|
|
162
|
+
* quietly counted these as fixed would be reporting a coverage gap as
|
|
163
|
+
* remediation, which is the worst thing this document could do.
|
|
164
|
+
* - `new` — this run's own finding, not part of what was being retested.
|
|
165
|
+
*/
|
|
166
|
+
export type RetestVerdict = 'fixed' | 'still_present' | 'returned' | 'not_retested' | 'new';
|
|
167
|
+
/** One issue, with what the retest established about it. */
|
|
168
|
+
export interface RetestEntry {
|
|
169
|
+
/** The issue as the snapshot sees it. */
|
|
170
|
+
readonly issue: SnapshotIssue;
|
|
171
|
+
/** What this run established about it. */
|
|
172
|
+
readonly verdict: RetestVerdict;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The difference between two runs.
|
|
176
|
+
*
|
|
177
|
+
* Present whenever the snapshot has a baseline, whatever the report kind — it
|
|
178
|
+
* is a fact about the data, not a feature of one template. The `retest` report
|
|
179
|
+
* requires it; the others may use it.
|
|
180
|
+
*/
|
|
181
|
+
export interface RetestOutcome {
|
|
182
|
+
/** The run being retested against. */
|
|
183
|
+
readonly baseline: RunSummary;
|
|
184
|
+
/** Every issue, most urgent first, with its verdict. */
|
|
185
|
+
readonly entries: readonly RetestEntry[];
|
|
186
|
+
/** How many issues fell into each verdict. */
|
|
187
|
+
readonly counts: Readonly<Record<RetestVerdict, number>>;
|
|
188
|
+
/**
|
|
189
|
+
* Fixed as a proportion of what could actually be checked, 0–1.
|
|
190
|
+
*
|
|
191
|
+
* **`not_retested` is excluded from the denominator, not counted as a
|
|
192
|
+
* failure.** An issue nobody looked at is neither fixed nor unfixed, and
|
|
193
|
+
* folding it either way turns a coverage gap into a number somebody quotes.
|
|
194
|
+
* `null` when there was nothing to check.
|
|
195
|
+
*/
|
|
196
|
+
readonly fixRate: number | null;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Derives everything a report shows, once, from a snapshot.
|
|
200
|
+
*
|
|
201
|
+
* Both renderers consume this rather than the snapshot, so a number in the
|
|
202
|
+
* Markdown and the same number in the HTML cannot drift apart — they are the
|
|
203
|
+
* same value formatted twice.
|
|
204
|
+
*
|
|
205
|
+
* Suppressed issues are already separated by the snapshot and stay separated
|
|
206
|
+
* here: they never reach {@link ReportModel.sections}, are excluded from
|
|
207
|
+
* {@link ReportModel.outstanding} and from the exposure score, and appear only
|
|
208
|
+
* in the suppressed appendix (invariant 7).
|
|
209
|
+
*
|
|
210
|
+
* @param snapshot - Issue state as of a run.
|
|
211
|
+
* @param options - Title, attribution, and the render time.
|
|
212
|
+
* @returns The model both renderers format.
|
|
213
|
+
*/
|
|
214
|
+
export declare function buildReportModel(snapshot: Snapshot, options: ReportOptions): ReportModel;
|
|
215
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/report/model.ts"],"names":[],"mappings":"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"}
|