@glassmkr/crucible 0.10.4 → 0.12.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/dist/collect/__tests__/c11-c18.test.d.ts +1 -0
- package/dist/collect/__tests__/c11-c18.test.js +375 -0
- package/dist/collect/__tests__/c11-c18.test.js.map +1 -0
- package/dist/collect/__tests__/c7-c10.test.d.ts +1 -0
- package/dist/collect/__tests__/c7-c10.test.js +271 -0
- package/dist/collect/__tests__/c7-c10.test.js.map +1 -0
- package/dist/collect/__tests__/systemd.test.js +10 -1
- package/dist/collect/__tests__/systemd.test.js.map +1 -1
- package/dist/collect/bonding.d.ts +37 -0
- package/dist/collect/bonding.js +246 -0
- package/dist/collect/bonding.js.map +1 -0
- package/dist/collect/conntrack.d.ts +19 -0
- package/dist/collect/conntrack.js +82 -1
- package/dist/collect/conntrack.js.map +1 -1
- package/dist/collect/cve.d.ts +51 -0
- package/dist/collect/cve.js +327 -0
- package/dist/collect/cve.js.map +1 -0
- package/dist/collect/dmesg-events.d.ts +32 -0
- package/dist/collect/dmesg-events.js +196 -0
- package/dist/collect/dmesg-events.js.map +1 -0
- package/dist/collect/ethtool.d.ts +29 -0
- package/dist/collect/ethtool.js +99 -0
- package/dist/collect/ethtool.js.map +1 -0
- package/dist/collect/fd.d.ts +46 -0
- package/dist/collect/fd.js +148 -0
- package/dist/collect/fd.js.map +1 -1
- package/dist/collect/ipmi.d.ts +19 -1
- package/dist/collect/ipmi.js +39 -2
- package/dist/collect/ipmi.js.map +1 -1
- package/dist/collect/lvm.d.ts +39 -0
- package/dist/collect/lvm.js +102 -0
- package/dist/collect/lvm.js.map +1 -0
- package/dist/collect/smart.d.ts +25 -0
- package/dist/collect/smart.js +36 -0
- package/dist/collect/smart.js.map +1 -1
- package/dist/collect/softnet.d.ts +17 -0
- package/dist/collect/softnet.js +82 -0
- package/dist/collect/softnet.js.map +1 -0
- package/dist/collect/systemd.d.ts +27 -2
- package/dist/collect/systemd.js +98 -5
- package/dist/collect/systemd.js.map +1 -1
- package/dist/collect/tcp-stats.d.ts +37 -0
- package/dist/collect/tcp-stats.js +153 -0
- package/dist/collect/tcp-stats.js.map +1 -0
- package/dist/index.js +48 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/types.d.ts +197 -1
- package/package.json +1 -1
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
// Conntrack collection.
|
|
2
|
+
//
|
|
3
|
+
// Pre-C9: count + max + percent from /proc/sys/net/netfilter/nf_conntrack_*.
|
|
4
|
+
// C9 (2026-05-19): adds insert_failed_total + drop_total cumulative counters
|
|
5
|
+
// from /proc/net/stat/nf_conntrack plus agent-computed per-second rates,
|
|
6
|
+
// following the vmstat (C3) rate-calculation pattern.
|
|
7
|
+
//
|
|
8
|
+
// Per CC_SPEC_CRUCIBLE_C7_C10_NETWORK_PROCESS_COLLECTION_2026-05-19.md §3.
|
|
1
9
|
import { readProcFile } from "../lib/parse.js";
|
|
10
|
+
let previous = null;
|
|
2
11
|
export function collectConntrack() {
|
|
3
12
|
const countRaw = readProcFile("/proc/sys/net/netfilter/nf_conntrack_count");
|
|
4
13
|
const maxRaw = readProcFile("/proc/sys/net/netfilter/nf_conntrack_max");
|
|
@@ -11,6 +20,78 @@ export function collectConntrack() {
|
|
|
11
20
|
return { available: false, count: 0, max: 0, percent: 0 };
|
|
12
21
|
}
|
|
13
22
|
const percent = Math.round(((count / max) * 100) * 10) / 10;
|
|
14
|
-
|
|
23
|
+
// Try the C9 enrichment. If /proc/net/stat/nf_conntrack isn't readable
|
|
24
|
+
// we still return the original ConntrackData shape (older kernels
|
|
25
|
+
// expose count/max without per-CPU stats).
|
|
26
|
+
const stat = parseConntrackStat();
|
|
27
|
+
if (!stat) {
|
|
28
|
+
return { available: true, count, max, percent };
|
|
29
|
+
}
|
|
30
|
+
const nowMs = Date.now();
|
|
31
|
+
let insertRate = null;
|
|
32
|
+
let dropRate = null;
|
|
33
|
+
if (previous) {
|
|
34
|
+
const elapsedSec = (nowMs - previous.capturedAtMs) / 1000;
|
|
35
|
+
if (elapsedSec > 0) {
|
|
36
|
+
const insertDelta = stat.insert_failed - previous.insert_failed;
|
|
37
|
+
const dropDelta = stat.drop - previous.drop;
|
|
38
|
+
// Negative delta = counter reset (host reboot, container restart,
|
|
39
|
+
// or rollover). Treat as a fresh baseline; rates null this tick.
|
|
40
|
+
if (insertDelta >= 0)
|
|
41
|
+
insertRate = insertDelta / elapsedSec;
|
|
42
|
+
if (dropDelta >= 0)
|
|
43
|
+
dropRate = dropDelta / elapsedSec;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
previous = { ...stat, capturedAtMs: nowMs };
|
|
47
|
+
return {
|
|
48
|
+
available: true,
|
|
49
|
+
count,
|
|
50
|
+
max,
|
|
51
|
+
percent,
|
|
52
|
+
insert_failed_total: stat.insert_failed,
|
|
53
|
+
drop_total: stat.drop,
|
|
54
|
+
insert_failed_rate_per_sec: insertRate,
|
|
55
|
+
drop_rate_per_sec: dropRate,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse /proc/net/stat/nf_conntrack. Format: tab/space-separated header
|
|
60
|
+
* + one row per CPU with hex values. Returns sums across all CPUs for
|
|
61
|
+
* insert_failed and drop columns. Null on read failure or unexpected
|
|
62
|
+
* format.
|
|
63
|
+
*/
|
|
64
|
+
function parseConntrackStat() {
|
|
65
|
+
const raw = readProcFile("/proc/net/stat/nf_conntrack");
|
|
66
|
+
if (!raw)
|
|
67
|
+
return null;
|
|
68
|
+
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
69
|
+
if (lines.length < 2)
|
|
70
|
+
return null;
|
|
71
|
+
const header = lines[0].trim().split(/\s+/);
|
|
72
|
+
const insertFailedIdx = header.indexOf("insert_failed");
|
|
73
|
+
const dropIdx = header.indexOf("drop");
|
|
74
|
+
if (insertFailedIdx === -1 || dropIdx === -1)
|
|
75
|
+
return null;
|
|
76
|
+
let insertFailedTotal = 0;
|
|
77
|
+
let dropTotal = 0;
|
|
78
|
+
for (let i = 1; i < lines.length; i++) {
|
|
79
|
+
const parts = lines[i].trim().split(/\s+/);
|
|
80
|
+
if (parts.length <= Math.max(insertFailedIdx, dropIdx))
|
|
81
|
+
continue;
|
|
82
|
+
const insertFailed = parseInt(parts[insertFailedIdx], 16);
|
|
83
|
+
const drop = parseInt(parts[dropIdx], 16);
|
|
84
|
+
if (Number.isFinite(insertFailed))
|
|
85
|
+
insertFailedTotal += insertFailed;
|
|
86
|
+
if (Number.isFinite(drop))
|
|
87
|
+
dropTotal += drop;
|
|
88
|
+
}
|
|
89
|
+
return { insert_failed: insertFailedTotal, drop: dropTotal };
|
|
15
90
|
}
|
|
91
|
+
export const __test_only = {
|
|
92
|
+
parseConntrackStat,
|
|
93
|
+
resetForTests: () => {
|
|
94
|
+
previous = null;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
16
97
|
//# sourceMappingURL=conntrack.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conntrack.js","sourceRoot":"","sources":["../../src/collect/conntrack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"conntrack.js","sourceRoot":"","sources":["../../src/collect/conntrack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CveDistro, CveSeverity, CveSnapshot, KernelCve } from "../lib/types.js";
|
|
2
|
+
export declare function collectCve(): Promise<CveSnapshot>;
|
|
3
|
+
declare function detectDistro(): CveDistro;
|
|
4
|
+
/**
|
|
5
|
+
* Parse the relevant kernel-CVE subset of `pro security-status --format=json`.
|
|
6
|
+
* The full shape is large; we only need pending CVEs against the
|
|
7
|
+
* running kernel + a severity histogram.
|
|
8
|
+
*
|
|
9
|
+
* Best-effort + defensive: malformed JSON yields zeros and no events.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseUbuntuProJson(raw: string): {
|
|
12
|
+
kernel_cves: KernelCve[];
|
|
13
|
+
critical: number;
|
|
14
|
+
important: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Parse `dnf updateinfo list --security --quiet` text output.
|
|
18
|
+
*
|
|
19
|
+
* Format (one line per advisory; columns vary slightly by dnf version):
|
|
20
|
+
* RHSA-2026:1234 Critical/Sec. kernel-5.14.0-1234.x86_64
|
|
21
|
+
* RHBA-2026:5678 Moderate/Sec. bash-5.1.8-9.el9_4.x86_64
|
|
22
|
+
*
|
|
23
|
+
* We only keep advisories whose package name starts with "kernel"
|
|
24
|
+
* (the kernel meta-package or any kernel-* sub-package).
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseDnfUpdateinfoText(raw: string): {
|
|
27
|
+
kernel_cves: KernelCve[];
|
|
28
|
+
critical: number;
|
|
29
|
+
important: number;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Parse `zypper list-patches --category=security` table output.
|
|
33
|
+
*
|
|
34
|
+
* Format (columns: Repository | Name | Category | Severity | Status):
|
|
35
|
+
* SLES15-SP6-Updates | SUSE-SLE-...-1234 | security | critical | needed
|
|
36
|
+
*
|
|
37
|
+
* We restrict to security patches whose name contains "kernel" — best
|
|
38
|
+
* effort; zypper doesn't surface a "package" column the same way dnf
|
|
39
|
+
* does, so the kernel match is on the patch name itself.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseZypperListPatchesText(raw: string): {
|
|
42
|
+
kernel_cves: KernelCve[];
|
|
43
|
+
critical: number;
|
|
44
|
+
important: number;
|
|
45
|
+
};
|
|
46
|
+
declare function normaliseSeverity(raw: string): CveSeverity;
|
|
47
|
+
export declare const __test_only: {
|
|
48
|
+
detectDistro: typeof detectDistro;
|
|
49
|
+
normaliseSeverity: typeof normaliseSeverity;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
// Distro-aware CVE collection for the running kernel.
|
|
2
|
+
//
|
|
3
|
+
// Pre-C13 the collector reads /sys/devices/system/cpu/vulnerabilities
|
|
4
|
+
// (Spectre / Meltdown / etc) under SecurityData.kernel_vulns. That's
|
|
5
|
+
// CPU microcode + kernel-mitigation status, not the distro CVE patch
|
|
6
|
+
// queue. C13 ships separate distro-CVE data so Dashboard can REDESIGN
|
|
7
|
+
// the kernel_vulnerabilities rule from a uptime-proxy / kernel-line
|
|
8
|
+
// check into a real CVE-driven signal.
|
|
9
|
+
//
|
|
10
|
+
// Three distro paths:
|
|
11
|
+
//
|
|
12
|
+
// - Ubuntu / Ubuntu Pro:
|
|
13
|
+
// Requires `pro security-status --format=json` AND attached pro
|
|
14
|
+
// subscription. Token comes from GLASSMKR_UBUNTU_PRO_TOKEN env
|
|
15
|
+
// var per the spec. No token => available: false silently
|
|
16
|
+
// (legitimate state on non-Pro hosts).
|
|
17
|
+
//
|
|
18
|
+
// - RHEL / Fedora / Rocky / Alma / CentOS:
|
|
19
|
+
// `dnf updateinfo --output json` exposes a per-advisory list.
|
|
20
|
+
// The dnf JSON output is well-defined on modern releases (8+);
|
|
21
|
+
// older dnf falls back to text scraping which we tag as "stub".
|
|
22
|
+
//
|
|
23
|
+
// - SUSE / openSUSE:
|
|
24
|
+
// `zypper list-patches --category=security --severity=critical`
|
|
25
|
+
// returns one line per patch. Severity is a column.
|
|
26
|
+
//
|
|
27
|
+
// Capability gating: missing CLI => available: false with reason.
|
|
28
|
+
// Distro detection uses snap.system.os_id (Crucible 0.8+ field); but
|
|
29
|
+
// since this collector is called separately from system.ts, we re-
|
|
30
|
+
// derive distro from /etc/os-release inside this module to stay
|
|
31
|
+
// independent.
|
|
32
|
+
//
|
|
33
|
+
// Per CC_SPEC_CRUCIBLE_C11_C18_FULL_BUNDLE_2026-05-19.md §3.
|
|
34
|
+
import { readProcFile } from "../lib/parse.js";
|
|
35
|
+
import { run } from "../lib/exec.js";
|
|
36
|
+
export async function collectCve() {
|
|
37
|
+
const distro = detectDistro();
|
|
38
|
+
switch (distro) {
|
|
39
|
+
case "ubuntu":
|
|
40
|
+
case "debian":
|
|
41
|
+
return collectUbuntuPro();
|
|
42
|
+
case "rhel":
|
|
43
|
+
case "fedora":
|
|
44
|
+
case "rocky":
|
|
45
|
+
case "alma":
|
|
46
|
+
case "centos":
|
|
47
|
+
return collectDnf(distro);
|
|
48
|
+
case "sles":
|
|
49
|
+
case "opensuse":
|
|
50
|
+
return collectZypper(distro);
|
|
51
|
+
default:
|
|
52
|
+
return {
|
|
53
|
+
available: false,
|
|
54
|
+
reason: `distro "${distro}" not supported by CVE collection`,
|
|
55
|
+
distro,
|
|
56
|
+
kernel_cves_pending: [],
|
|
57
|
+
total_critical_pending: 0,
|
|
58
|
+
total_important_pending: 0,
|
|
59
|
+
parser_quality: "stub",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function detectDistro() {
|
|
64
|
+
const raw = readProcFile("/etc/os-release");
|
|
65
|
+
if (!raw)
|
|
66
|
+
return "unknown";
|
|
67
|
+
for (const line of raw.split("\n")) {
|
|
68
|
+
if (line.startsWith("ID=")) {
|
|
69
|
+
const id = line.slice(3).trim().replace(/^"|"$/g, "").toLowerCase();
|
|
70
|
+
if (id === "ubuntu")
|
|
71
|
+
return "ubuntu";
|
|
72
|
+
if (id === "debian")
|
|
73
|
+
return "debian";
|
|
74
|
+
if (id === "rhel")
|
|
75
|
+
return "rhel";
|
|
76
|
+
if (id === "fedora")
|
|
77
|
+
return "fedora";
|
|
78
|
+
if (id === "rocky")
|
|
79
|
+
return "rocky";
|
|
80
|
+
if (id === "almalinux" || id === "alma")
|
|
81
|
+
return "alma";
|
|
82
|
+
if (id === "centos")
|
|
83
|
+
return "centos";
|
|
84
|
+
if (id === "sles")
|
|
85
|
+
return "sles";
|
|
86
|
+
if (id === "opensuse" || id === "opensuse-leap" || id === "opensuse-tumbleweed") {
|
|
87
|
+
return "opensuse";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return "unknown";
|
|
92
|
+
}
|
|
93
|
+
// === Ubuntu Pro path ===
|
|
94
|
+
async function collectUbuntuPro() {
|
|
95
|
+
const token = process.env.GLASSMKR_UBUNTU_PRO_TOKEN;
|
|
96
|
+
if (!token) {
|
|
97
|
+
return {
|
|
98
|
+
available: false,
|
|
99
|
+
reason: "Ubuntu Pro token not set (export GLASSMKR_UBUNTU_PRO_TOKEN to enable CVE collection)",
|
|
100
|
+
distro: "ubuntu",
|
|
101
|
+
kernel_cves_pending: [],
|
|
102
|
+
total_critical_pending: 0,
|
|
103
|
+
total_important_pending: 0,
|
|
104
|
+
parser_quality: "fleet-tested",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const out = await run("pro", ["security-status", "--format=json"]);
|
|
108
|
+
if (!out) {
|
|
109
|
+
return {
|
|
110
|
+
available: false,
|
|
111
|
+
reason: "`pro security-status` returned no output (Ubuntu Pro CLI missing or not attached?)",
|
|
112
|
+
distro: "ubuntu",
|
|
113
|
+
kernel_cves_pending: [],
|
|
114
|
+
total_critical_pending: 0,
|
|
115
|
+
total_important_pending: 0,
|
|
116
|
+
parser_quality: "fleet-tested",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const parsed = parseUbuntuProJson(out);
|
|
120
|
+
return {
|
|
121
|
+
available: true,
|
|
122
|
+
distro: "ubuntu",
|
|
123
|
+
kernel_cves_pending: parsed.kernel_cves,
|
|
124
|
+
total_critical_pending: parsed.critical,
|
|
125
|
+
total_important_pending: parsed.important,
|
|
126
|
+
parser_quality: "fleet-tested",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Parse the relevant kernel-CVE subset of `pro security-status --format=json`.
|
|
131
|
+
* The full shape is large; we only need pending CVEs against the
|
|
132
|
+
* running kernel + a severity histogram.
|
|
133
|
+
*
|
|
134
|
+
* Best-effort + defensive: malformed JSON yields zeros and no events.
|
|
135
|
+
*/
|
|
136
|
+
export function parseUbuntuProJson(raw) {
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = JSON.parse(raw);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return { kernel_cves: [], critical: 0, important: 0 };
|
|
143
|
+
}
|
|
144
|
+
// Ubuntu Pro JSON shape (abbreviated; real output has many more fields):
|
|
145
|
+
// { "summary": { "kernel-cves": { "pending": [{ "cve": "CVE-2026-1234",
|
|
146
|
+
// "severity": "high", "package": "linux-image-...", ... }] } } }
|
|
147
|
+
// The exact key shape varies by pro CLI version; reach defensively.
|
|
148
|
+
const root = parsed;
|
|
149
|
+
const pendingArr = root?.summary?.["kernel-cves"]?.pending ??
|
|
150
|
+
root?.["kernel-cves"] ??
|
|
151
|
+
[];
|
|
152
|
+
const cves = [];
|
|
153
|
+
let crit = 0;
|
|
154
|
+
let imp = 0;
|
|
155
|
+
if (Array.isArray(pendingArr)) {
|
|
156
|
+
for (const entry of pendingArr) {
|
|
157
|
+
const e = entry;
|
|
158
|
+
const cveId = typeof e.cve === "string" ? e.cve : "";
|
|
159
|
+
if (!cveId)
|
|
160
|
+
continue;
|
|
161
|
+
const severity = normaliseSeverity(typeof e.severity === "string" ? e.severity : "");
|
|
162
|
+
const pkg = typeof e.package === "string" ? e.package : "";
|
|
163
|
+
const fixed = typeof e.fixed_version === "string" ? e.fixed_version : undefined;
|
|
164
|
+
cves.push({
|
|
165
|
+
cve_id: cveId,
|
|
166
|
+
severity,
|
|
167
|
+
package_name: pkg,
|
|
168
|
+
...(fixed ? { fixed_version: fixed } : {}),
|
|
169
|
+
});
|
|
170
|
+
if (severity === "critical")
|
|
171
|
+
crit++;
|
|
172
|
+
else if (severity === "important")
|
|
173
|
+
imp++;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return { kernel_cves: cves, critical: crit, important: imp };
|
|
177
|
+
}
|
|
178
|
+
// === dnf path (RHEL family) ===
|
|
179
|
+
async function collectDnf(distro) {
|
|
180
|
+
const out = await run("dnf", [
|
|
181
|
+
"updateinfo",
|
|
182
|
+
"list",
|
|
183
|
+
"--security",
|
|
184
|
+
"--quiet",
|
|
185
|
+
]);
|
|
186
|
+
if (!out) {
|
|
187
|
+
return {
|
|
188
|
+
available: false,
|
|
189
|
+
reason: "`dnf updateinfo list --security` returned no output (dnf missing or no security advisories?)",
|
|
190
|
+
distro,
|
|
191
|
+
kernel_cves_pending: [],
|
|
192
|
+
total_critical_pending: 0,
|
|
193
|
+
total_important_pending: 0,
|
|
194
|
+
parser_quality: "stub",
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const parsed = parseDnfUpdateinfoText(out);
|
|
198
|
+
return {
|
|
199
|
+
available: true,
|
|
200
|
+
distro,
|
|
201
|
+
kernel_cves_pending: parsed.kernel_cves,
|
|
202
|
+
total_critical_pending: parsed.critical,
|
|
203
|
+
total_important_pending: parsed.important,
|
|
204
|
+
// Text scrape; dnf JSON output is the cleaner path but isn't
|
|
205
|
+
// universally available across RHEL 8/9/10. Tagging stub so the
|
|
206
|
+
// dashboard rule shows the right honesty.
|
|
207
|
+
parser_quality: "stub",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parse `dnf updateinfo list --security --quiet` text output.
|
|
212
|
+
*
|
|
213
|
+
* Format (one line per advisory; columns vary slightly by dnf version):
|
|
214
|
+
* RHSA-2026:1234 Critical/Sec. kernel-5.14.0-1234.x86_64
|
|
215
|
+
* RHBA-2026:5678 Moderate/Sec. bash-5.1.8-9.el9_4.x86_64
|
|
216
|
+
*
|
|
217
|
+
* We only keep advisories whose package name starts with "kernel"
|
|
218
|
+
* (the kernel meta-package or any kernel-* sub-package).
|
|
219
|
+
*/
|
|
220
|
+
export function parseDnfUpdateinfoText(raw) {
|
|
221
|
+
const cves = [];
|
|
222
|
+
let crit = 0;
|
|
223
|
+
let imp = 0;
|
|
224
|
+
for (const line of raw.split("\n")) {
|
|
225
|
+
const m = line.match(/^([A-Z]+-\d{4}:\d+)\s+(\S+)\/Sec\.\s+(\S+)/i);
|
|
226
|
+
if (!m)
|
|
227
|
+
continue;
|
|
228
|
+
const [, advisory, sevToken, pkg] = m;
|
|
229
|
+
if (!pkg.toLowerCase().startsWith("kernel"))
|
|
230
|
+
continue;
|
|
231
|
+
const severity = normaliseSeverity(sevToken);
|
|
232
|
+
cves.push({
|
|
233
|
+
cve_id: advisory, // dnf reports advisory IDs (RHSA-...) not CVE IDs directly
|
|
234
|
+
severity,
|
|
235
|
+
package_name: pkg,
|
|
236
|
+
});
|
|
237
|
+
if (severity === "critical")
|
|
238
|
+
crit++;
|
|
239
|
+
else if (severity === "important")
|
|
240
|
+
imp++;
|
|
241
|
+
}
|
|
242
|
+
return { kernel_cves: cves, critical: crit, important: imp };
|
|
243
|
+
}
|
|
244
|
+
// === zypper path (SUSE family) ===
|
|
245
|
+
async function collectZypper(distro) {
|
|
246
|
+
const out = await run("zypper", [
|
|
247
|
+
"--non-interactive",
|
|
248
|
+
"list-patches",
|
|
249
|
+
"--category=security",
|
|
250
|
+
]);
|
|
251
|
+
if (!out) {
|
|
252
|
+
return {
|
|
253
|
+
available: false,
|
|
254
|
+
reason: "`zypper list-patches --category=security` returned no output (zypper missing?)",
|
|
255
|
+
distro,
|
|
256
|
+
kernel_cves_pending: [],
|
|
257
|
+
total_critical_pending: 0,
|
|
258
|
+
total_important_pending: 0,
|
|
259
|
+
parser_quality: "stub",
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
const parsed = parseZypperListPatchesText(out);
|
|
263
|
+
return {
|
|
264
|
+
available: true,
|
|
265
|
+
distro,
|
|
266
|
+
kernel_cves_pending: parsed.kernel_cves,
|
|
267
|
+
total_critical_pending: parsed.critical,
|
|
268
|
+
total_important_pending: parsed.important,
|
|
269
|
+
parser_quality: "stub",
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Parse `zypper list-patches --category=security` table output.
|
|
274
|
+
*
|
|
275
|
+
* Format (columns: Repository | Name | Category | Severity | Status):
|
|
276
|
+
* SLES15-SP6-Updates | SUSE-SLE-...-1234 | security | critical | needed
|
|
277
|
+
*
|
|
278
|
+
* We restrict to security patches whose name contains "kernel" — best
|
|
279
|
+
* effort; zypper doesn't surface a "package" column the same way dnf
|
|
280
|
+
* does, so the kernel match is on the patch name itself.
|
|
281
|
+
*/
|
|
282
|
+
export function parseZypperListPatchesText(raw) {
|
|
283
|
+
const cves = [];
|
|
284
|
+
let crit = 0;
|
|
285
|
+
let imp = 0;
|
|
286
|
+
for (const line of raw.split("\n")) {
|
|
287
|
+
if (!line.includes("|"))
|
|
288
|
+
continue;
|
|
289
|
+
const cols = line.split("|").map((c) => c.trim());
|
|
290
|
+
if (cols.length < 5)
|
|
291
|
+
continue;
|
|
292
|
+
const [, name, category, severityRaw] = cols;
|
|
293
|
+
if (!/security/i.test(category))
|
|
294
|
+
continue;
|
|
295
|
+
if (!/kernel/i.test(name))
|
|
296
|
+
continue;
|
|
297
|
+
const severity = normaliseSeverity(severityRaw);
|
|
298
|
+
cves.push({
|
|
299
|
+
cve_id: name,
|
|
300
|
+
severity,
|
|
301
|
+
package_name: name,
|
|
302
|
+
});
|
|
303
|
+
if (severity === "critical")
|
|
304
|
+
crit++;
|
|
305
|
+
else if (severity === "important")
|
|
306
|
+
imp++;
|
|
307
|
+
}
|
|
308
|
+
return { kernel_cves: cves, critical: crit, important: imp };
|
|
309
|
+
}
|
|
310
|
+
// === shared helpers ===
|
|
311
|
+
function normaliseSeverity(raw) {
|
|
312
|
+
const v = raw.toLowerCase().trim();
|
|
313
|
+
if (v === "critical" || v === "crit")
|
|
314
|
+
return "critical";
|
|
315
|
+
if (v === "important" || v === "high" || v === "imp")
|
|
316
|
+
return "important";
|
|
317
|
+
if (v === "moderate" || v === "medium" || v === "med")
|
|
318
|
+
return "moderate";
|
|
319
|
+
if (v === "low" || v === "negligible")
|
|
320
|
+
return "low";
|
|
321
|
+
return "unknown";
|
|
322
|
+
}
|
|
323
|
+
export const __test_only = {
|
|
324
|
+
detectDistro,
|
|
325
|
+
normaliseSeverity,
|
|
326
|
+
};
|
|
327
|
+
//# sourceMappingURL=cve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cve.js","sourceRoot":"","sources":["../../src/collect/cve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DmesgEventType, DmesgEventsSnapshot, DmesgStructuredEvent } from "../lib/types.js";
|
|
2
|
+
interface DmesgHandler {
|
|
3
|
+
event_type: DmesgEventType;
|
|
4
|
+
pattern: RegExp;
|
|
5
|
+
/** Returns null when the regex matched on accident (rare). */
|
|
6
|
+
parse(match: RegExpMatchArray, line: string): Omit<DmesgStructuredEvent, "timestamp_iso" | "raw_line"> | null;
|
|
7
|
+
}
|
|
8
|
+
export declare function collectDmesgEvents(): Promise<DmesgEventsSnapshot>;
|
|
9
|
+
/**
|
|
10
|
+
* Parse a full dmesg output buffer; return structured events whose
|
|
11
|
+
* inferred timestamp is at or after `cutoffMs`. When the timestamp
|
|
12
|
+
* cannot be parsed (relative-time fallback), the event is included
|
|
13
|
+
* unconditionally (fail-open: better to over-report than silently
|
|
14
|
+
* drop a real hardware fault).
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseDmesgOutput(raw: string, cutoffMs: number): DmesgStructuredEvent[];
|
|
17
|
+
/**
|
|
18
|
+
* Extract a unix-ms timestamp from a dmesg line. Two shapes:
|
|
19
|
+
* ISO: "2026-05-19T12:34:56,789012+00:00 ..." (--time-format=iso)
|
|
20
|
+
* ctime: "[Mon May 19 12:34:56 2026] ..." (--ctime)
|
|
21
|
+
*
|
|
22
|
+
* Relative-time format ("[12345.678]") returns null (no absolute
|
|
23
|
+
* anchor available without `uptime`).
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseDmesgTimestamp(line: string): number | null;
|
|
26
|
+
export declare const __test_only: {
|
|
27
|
+
parseDmesgOutput: typeof parseDmesgOutput;
|
|
28
|
+
parseDmesgTimestamp: typeof parseDmesgTimestamp;
|
|
29
|
+
HANDLERS: DmesgHandler[];
|
|
30
|
+
WINDOW_SECONDS: number;
|
|
31
|
+
};
|
|
32
|
+
export {};
|