Repository navigation
Expand file tree
/
Copy pathreporting.ts
More file actions
86 lines (72 loc) · 2.91 KB
/
Copy pathreporting.ts
File metadata and controls
86 lines (72 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { getBlockedCommandReason, normalizeForPolicy } from "./policy.js";
export type SecuritySeverity = "low" | "medium" | "high" | "critical";
export type SecuritySuiteResult = {
name: string;
status: "pass" | "fail";
severity: SecuritySeverity;
details: string;
};
export function addSecurityResult(results: SecuritySuiteResult[], name: string, status: "pass" | "fail", severity: SecuritySeverity, details: string) {
results.push({ name, status, severity, details });
}
export function assertCommandBlockedWithToken(name: string, command: string, expectedToken: string, severity: SecuritySeverity = "critical"): SecuritySuiteResult {
const reason = getBlockedCommandReason(command);
const pass = reason !== null && normalizeForPolicy(reason).includes(normalizeForPolicy(expectedToken));
return {
name,
status: pass ? "pass" : "fail",
severity,
details: pass ? `Command blocked with expected token: ${expectedToken}` : `Expected token '${expectedToken}' not found in block reason. Reason: ${reason || "none"}`,
};
}
export function getHighestSeverity(results: SecuritySuiteResult[]): SecuritySeverity {
const order: SecuritySeverity[] = ["low", "medium", "high", "critical"];
let highest: SecuritySeverity = "low";
for (const r of results) {
if (order.indexOf(r.severity) > order.indexOf(highest)) {
highest = r.severity;
}
}
return highest;
}
function sortResultsForTriage(results: SecuritySuiteResult[]): SecuritySuiteResult[] {
const severityOrder: Record<SecuritySeverity, number> = {
critical: 0,
high: 1,
medium: 2,
low: 3,
};
const statusOrder: Record<SecuritySuiteResult["status"], number> = {
fail: 0,
pass: 1,
};
return [...results].sort((a, b) => {
const bySeverity = severityOrder[a.severity] - severityOrder[b.severity];
if (bySeverity !== 0) return bySeverity;
const byStatus = statusOrder[a.status] - statusOrder[b.status];
if (byStatus !== 0) return byStatus;
return a.name.localeCompare(b.name);
});
}
export function renderSuiteReport(outputId: string, suiteName: string, results: SecuritySuiteResult[]) {
const output = document.getElementById(outputId);
const sortedResults = sortResultsForTriage(results);
const failed = results.filter((r) => r.status === "fail").length;
const passed = results.length - failed;
const highestSeverity = getHighestSeverity(results);
const report = {
generatedAt: new Date().toISOString(),
suite: suiteName,
summary: {
total: results.length,
passed,
failed,
highestSeverity,
},
results: sortedResults,
};
if (output) {
output.textContent = JSON.stringify(report, null, 2);
}
return { failed, passed, total: results.length, highestSeverity };
}