///
import {
type Cell,
cell,
Default,
handler,
lift,
recipe,
str,
} from "commontools";
type Severity = "critical" | "high" | "medium" | "low";
type Status = "open" | "in_progress" | "resolved";
interface VulnerabilityEntry {
id: string;
system: string;
severity: Severity;
status: Status;
score: number;
}
interface SecurityVulnerabilityTrackerArgs {
vulnerabilities: Default;
}
interface SeverityRollup {
critical: number;
high: number;
medium: number;
low: number;
}
interface SystemRiskEntry {
system: string;
risk: number;
}
interface RiskSnapshot {
total: number;
bySeverity: SeverityRollup;
bySystem: SystemRiskEntry[];
}
type AuditAction = "init" | "registered" | "updated" | "resolved";
interface VulnerabilityAudit {
action: AuditAction;
id: string;
severity: Severity;
status: Status;
system: string;
score: number;
}
const SEVERITY_SEQUENCE: readonly Severity[] = [
"critical",
"high",
"medium",
"low",
];
const SEVERITY_WEIGHTS: Record = {
critical: 5,
high: 3,
medium: 2,
low: 1,
};
const emptySeverityRollup = (): SeverityRollup => ({
critical: 0,
high: 0,
medium: 0,
low: 0,
});
const sanitizeId = (value: unknown, fallback: string): string => {
if (typeof value !== "string") {
return fallback;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : fallback;
};
const ensureUniqueId = (
candidate: string,
existing: readonly VulnerabilityEntry[],
): string => {
if (!existing.some((entry) => entry.id === candidate)) {
return candidate;
}
let index = 2;
while (existing.some((entry) => entry.id === `${candidate}-${index}`)) {
index += 1;
}
return `${candidate}-${index}`;
};
const sanitizeSeverity = (value: unknown): Severity => {
if (typeof value !== "string") {
return "medium";
}
const normalized = value.toLowerCase();
if (
normalized === "critical" || normalized === "high" ||
normalized === "medium" || normalized === "low"
) {
return normalized as Severity;
}
return "medium";
};
const sanitizeStatus = (value: unknown): Status => {
if (typeof value !== "string") {
return "open";
}
const normalized = value.toLowerCase().replace(/[\s-]+/g, "_");
if (
normalized === "open" || normalized === "in_progress" ||
normalized === "resolved"
) {
return normalized as Status;
}
return "open";
};
const sanitizeSystem = (value: unknown): string => {
if (typeof value !== "string") {
return "unknown";
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : "unknown";
};
const sanitizeScore = (value: unknown, severity: Severity): number => {
if (typeof value !== "number" || !Number.isFinite(value)) {
return SEVERITY_WEIGHTS[severity];
}
const normalized = Math.max(0, Math.round(value * 10) / 10);
if (!Number.isFinite(normalized)) {
return SEVERITY_WEIGHTS[severity];
}
return normalized;
};
const sanitizeVulnerability = (raw: unknown): VulnerabilityEntry => {
const typed = typeof raw === "object" && raw !== null
? raw as Record
: {};
const severity = sanitizeSeverity(typed["severity"]);
const status = sanitizeStatus(typed["status"]);
const system = sanitizeSystem(typed["system"]);
const id = sanitizeId(typed["id"], "vuln-unknown");
const score = sanitizeScore(typed["score"], severity);
return { id, system, severity, status, score };
};
const sanitizeVulnerabilityList = (
input: unknown,
): VulnerabilityEntry[] => {
if (!Array.isArray(input)) {
return [];
}
const sanitized: VulnerabilityEntry[] = [];
for (const raw of input) {
const record = sanitizeVulnerability(raw);
const uniqueId = ensureUniqueId(record.id, sanitized);
sanitized.push(
uniqueId === record.id ? record : { ...record, id: uniqueId },
);
}
return sanitized;
};
const summarizeBySeverity = (
entries: readonly VulnerabilityEntry[],
): SeverityRollup => {
const totals = emptySeverityRollup();
for (const entry of entries) {
totals[entry.severity] += entry.score;
}
return totals;
};
const summarizeBySystem = (
entries: readonly VulnerabilityEntry[],
): Record => {
const totals: Record = {};
for (const entry of entries) {
const current = totals[entry.system] ?? 0;
totals[entry.system] = Math.round((current + entry.score) * 10) / 10;
}
return totals;
};
const buildSystemEntries = (
totals: Record,
): SystemRiskEntry[] => {
const entries: SystemRiskEntry[] = [];
for (const [system, risk] of Object.entries(totals)) {
const numeric = typeof risk === "number" && Number.isFinite(risk)
? Math.round(risk * 10) / 10
: 0;
entries.push({ system, risk: numeric });
}
entries.sort((left, right) => {
if (right.risk === left.risk) {
return left.system.localeCompare(right.system);
}
return right.risk - left.risk;
});
return entries;
};
const toNonNegativeInteger = (value: unknown): number => {
if (typeof value !== "number" || !Number.isFinite(value)) {
return 0;
}
const normalized = Math.floor(value);
return normalized >= 0 ? normalized : 0;
};
const recordAudit = (
audit: Cell,
entry: VulnerabilityAudit,
) => {
audit.set(entry);
};
export const securityVulnerabilityTracker = recipe<
SecurityVulnerabilityTrackerArgs
>(
"Security Vulnerability Tracker",
({ vulnerabilities }) => {
const sequence = cell(0);
const audit = cell({
action: "init",
id: "init",
severity: "low",
status: "open",
system: "unknown",
score: 0,
});
const vulnerabilitiesView = lift(sanitizeVulnerabilityList)(
vulnerabilities,
);
const activeVulnerabilities = lift(
(entries: readonly VulnerabilityEntry[]) =>
entries.filter((entry) => entry.status !== "resolved"),
)(vulnerabilitiesView);
const totals = lift((entries: readonly VulnerabilityEntry[]) => {
const plain = sanitizeVulnerabilityList(entries);
const active = plain.filter((entry) => entry.status !== "resolved");
const severity = summarizeBySeverity(active);
const systems = buildSystemEntries(summarizeBySystem(active));
const total = SEVERITY_SEQUENCE.reduce(
(sum, key) => Math.round((sum + severity[key]) * 10) / 10,
0,
);
const severityListValue = SEVERITY_SEQUENCE.map((severityKey) => ({
severity: severityKey,
risk: severity[severityKey],
}));
const activeCount = systems.length;
const label = activeCount === 1 ? "system" : "systems";
return {
severity,
systems,
total,
activeCount,
severityList: severityListValue,
label,
};
})(vulnerabilitiesView);
const severityTotals = lift((value: {
severity: SeverityRollup;
}) => value.severity)(totals);
const systemSummary = lift((value: {
systems: SystemRiskEntry[];
}) => value.systems)(totals);
const totalRisk = lift((value: { total: number }) => value.total)(totals);
const activeSystems = lift((value: { activeCount: number }) =>
value.activeCount
)(totals);
const systemLabel = lift((value: { label: string }) => value.label)(
totals,
);
const severityList = lift((value: {
severityList: {
severity: Severity;
risk: number;
}[];
}) => value.severityList)(totals);
const snapshot = lift((value: {
total: number;
severity: SeverityRollup;
systems: SystemRiskEntry[];
}) => ({
total: value.total,
bySeverity: value.severity,
bySystem: value.systems,
}))(totals);
const summaryLabel =
str`Risk total ${totalRisk} across ${activeSystems} ${systemLabel}`;
const register = handler(
(
event:
| {
id?: unknown;
system?: unknown;
severity?: unknown;
status?: unknown;
score?: unknown;
}
| undefined,
context: {
vulnerabilities: Cell;
sequence: Cell;
audit: Cell;
},
) => {
const sequenceValue = toNonNegativeInteger(context.sequence.get());
const fallbackId = `vuln-${sequenceValue + 1}`;
const existing = sanitizeVulnerabilityList(
context.vulnerabilities.get(),
);
const severity = sanitizeSeverity(event?.severity);
const status = sanitizeStatus(event?.status);
const system = sanitizeSystem(event?.system);
const score = sanitizeScore(event?.score, severity);
const id = ensureUniqueId(
sanitizeId(event?.id, fallbackId),
existing,
);
context.sequence.set(sequenceValue + 1);
const record: VulnerabilityEntry = {
id,
system,
severity,
status,
score,
};
const nextRecords = [...existing, record];
context.vulnerabilities.set(nextRecords);
recordAudit(context.audit, {
action: "registered",
id,
severity,
status,
system,
score,
});
},
);
const update = handler(
(
event:
| {
id?: unknown;
system?: unknown;
severity?: unknown;
status?: unknown;
score?: unknown;
}
| undefined,
context: {
vulnerabilities: Cell;
audit: Cell;
},
) => {
const id = sanitizeId(event?.id, "");
if (id.length === 0) {
return;
}
const existing = sanitizeVulnerabilityList(
context.vulnerabilities.get(),
);
let updated: VulnerabilityEntry | undefined;
const next = existing.map((entry) => {
if (entry.id !== id) {
return entry;
}
const severity = event?.severity === undefined
? entry.severity
: sanitizeSeverity(event?.severity);
const status = event?.status === undefined
? entry.status
: sanitizeStatus(event?.status);
const system = event?.system === undefined
? entry.system
: sanitizeSystem(event?.system);
const score = event?.score === undefined
? SEVERITY_WEIGHTS[severity]
: sanitizeScore(event?.score, severity);
updated = { id, severity, status, system, score };
return updated;
});
if (!updated) {
return;
}
context.vulnerabilities.set(next);
recordAudit(context.audit, { action: "updated", ...updated });
},
);
const resolve = handler(
(
event: { id?: unknown } | undefined,
context: {
vulnerabilities: Cell;
audit: Cell;
},
) => {
const id = sanitizeId(event?.id, "");
if (id.length === 0) {
return;
}
const existing = sanitizeVulnerabilityList(
context.vulnerabilities.get(),
);
let resolved: VulnerabilityEntry | undefined;
let changed = false;
const next = existing.map((entry) => {
if (entry.id !== id) {
return entry;
}
if (entry.status === "resolved") {
resolved = entry;
return entry;
}
resolved = { ...entry, status: "resolved", score: 0 };
changed = true;
return resolved;
});
if (!changed || !resolved) {
return;
}
context.vulnerabilities.set(next);
recordAudit(context.audit, { action: "resolved", ...resolved });
},
);
const auditView = lift(
(entry: VulnerabilityAudit | undefined) =>
entry ?? {
action: "init",
id: "init",
severity: "low",
status: "open",
system: "unknown",
score: 0,
},
)(audit);
return {
vulnerabilities,
vulnerabilitiesView,
activeVulnerabilities,
totals: {
severity: severityTotals,
system: systemSummary,
total: totalRisk,
},
severityList,
snapshot,
summaryLabel,
handlers: {
register: register({ vulnerabilities, sequence, audit }),
update: update({ vulnerabilities, audit }),
resolve: resolve({ vulnerabilities, audit }),
},
audit: auditView,
};
},
);