@sonde/packs 0.1.2 → 0.1.4
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/.turbo/turbo-build.log +6 -4
- package/.turbo/turbo-test.log +1343 -53
- package/CHANGELOG.md +18 -0
- package/dist/docker/manifest (# Edit conflict 2026-02-19 LIl7ilN #).js +54 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/a10.d.ts +3 -0
- package/dist/integrations/a10.d.ts.map +1 -0
- package/dist/integrations/a10.js +218 -0
- package/dist/integrations/a10.js.map +1 -0
- package/dist/integrations/checkpoint.d.ts +3 -0
- package/dist/integrations/checkpoint.d.ts.map +1 -0
- package/dist/integrations/checkpoint.js +249 -0
- package/dist/integrations/checkpoint.js.map +1 -0
- package/dist/integrations/datadog.d.ts +3 -0
- package/dist/integrations/datadog.d.ts.map +1 -0
- package/dist/integrations/datadog.js +195 -0
- package/dist/integrations/datadog.js.map +1 -0
- package/dist/integrations/jira.d.ts +3 -0
- package/dist/integrations/jira.d.ts.map +1 -0
- package/dist/integrations/jira.js +199 -0
- package/dist/integrations/jira.js.map +1 -0
- package/dist/integrations/loki.d.ts +3 -0
- package/dist/integrations/loki.d.ts.map +1 -0
- package/dist/integrations/loki.js +178 -0
- package/dist/integrations/loki.js.map +1 -0
- package/dist/integrations/meraki.d.ts +3 -0
- package/dist/integrations/meraki.d.ts.map +1 -0
- package/dist/integrations/meraki.js +238 -0
- package/dist/integrations/meraki.js.map +1 -0
- package/dist/integrations/pagerduty.d.ts +3 -0
- package/dist/integrations/pagerduty.d.ts.map +1 -0
- package/dist/integrations/pagerduty.js +229 -0
- package/dist/integrations/pagerduty.js.map +1 -0
- package/dist/integrations/thousandeyes.d.ts +3 -0
- package/dist/integrations/thousandeyes.d.ts.map +1 -0
- package/dist/integrations/thousandeyes.js +263 -0
- package/dist/integrations/thousandeyes.js.map +1 -0
- package/dist/integrations/vcenter.d.ts +3 -0
- package/dist/integrations/vcenter.d.ts.map +1 -0
- package/dist/integrations/vcenter.js +190 -0
- package/dist/integrations/vcenter.js.map +1 -0
- package/dist/proxmox/probes/ceph-status.test.d.ts (# Edit conflict 2026-02-19 N25hAvJ #).map +1 -0
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +8 -0
- package/dist/system/index.js.map +1 -1
- package/dist/system/manifest.d.ts.map +1 -1
- package/dist/system/manifest.js +82 -3
- package/dist/system/manifest.js.map +1 -1
- package/dist/system/probes/logs-dmesg.d.ts +13 -0
- package/dist/system/probes/logs-dmesg.d.ts.map +1 -0
- package/dist/system/probes/logs-dmesg.js +22 -0
- package/dist/system/probes/logs-dmesg.js.map +1 -0
- package/dist/system/probes/logs-dmesg.test.d.ts +2 -0
- package/dist/system/probes/logs-dmesg.test.d.ts.map +1 -0
- package/dist/system/probes/logs-dmesg.test.js +55 -0
- package/dist/system/probes/logs-dmesg.test.js.map +1 -0
- package/dist/system/probes/logs-journal.d.ts +21 -0
- package/dist/system/probes/logs-journal.d.ts.map +1 -0
- package/dist/system/probes/logs-journal.js +70 -0
- package/dist/system/probes/logs-journal.js.map +1 -0
- package/dist/system/probes/logs-journal.test.d.ts +2 -0
- package/dist/system/probes/logs-journal.test.d.ts.map +1 -0
- package/dist/system/probes/logs-journal.test.js +113 -0
- package/dist/system/probes/logs-journal.test.js.map +1 -0
- package/dist/system/probes/logs-tail.d.ts +14 -0
- package/dist/system/probes/logs-tail.d.ts.map +1 -0
- package/dist/system/probes/logs-tail.js +40 -0
- package/dist/system/probes/logs-tail.js.map +1 -0
- package/dist/system/probes/logs-tail.test.d.ts +2 -0
- package/dist/system/probes/logs-tail.test.d.ts.map +1 -0
- package/dist/system/probes/logs-tail.test.js +82 -0
- package/dist/system/probes/logs-tail.test.js.map +1 -0
- package/dist/system/probes/traceroute.d.ts +17 -0
- package/dist/system/probes/traceroute.d.ts.map +1 -0
- package/dist/system/probes/traceroute.js +72 -0
- package/dist/system/probes/traceroute.js.map +1 -0
- package/dist/system/probes/traceroute.test.d.ts +2 -0
- package/dist/system/probes/traceroute.test.d.ts.map +1 -0
- package/dist/system/probes/traceroute.test.js +98 -0
- package/dist/system/probes/traceroute.test.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +9 -0
- package/src/integrations/a10.ts +370 -0
- package/src/integrations/checkpoint.ts +381 -0
- package/src/integrations/datadog.ts +281 -0
- package/src/integrations/jira.ts +272 -0
- package/src/integrations/loki.ts +228 -0
- package/src/integrations/meraki.ts +344 -0
- package/src/integrations/pagerduty.ts +319 -0
- package/src/integrations/thousandeyes.ts +353 -0
- package/src/integrations/vcenter.ts +261 -0
- package/src/system/index.ts +8 -0
- package/src/system/manifest.ts +93 -3
- package/src/system/probes/logs-dmesg.test.ts +83 -0
- package/src/system/probes/logs-dmesg.ts +38 -0
- package/src/system/probes/logs-journal.test.ts +142 -0
- package/src/system/probes/logs-journal.ts +103 -0
- package/src/system/probes/logs-tail.test.ts +140 -0
- package/src/system/probes/logs-tail.ts +70 -0
- package/src/system/probes/traceroute.test.ts +149 -0
- package/src/system/probes/traceroute.ts +99 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { platform } from 'node:os';
|
|
2
|
+
/**
|
|
3
|
+
* Reads the kernel ring buffer via `dmesg`.
|
|
4
|
+
* On Linux uses `--time-format iso` for readable timestamps.
|
|
5
|
+
* On macOS uses plain `dmesg` (no --time-format support).
|
|
6
|
+
*/
|
|
7
|
+
export const logsDmesg = async (params, exec) => {
|
|
8
|
+
const lines = Math.min(Math.max(Number(params?.lines ?? 50), 1), 500);
|
|
9
|
+
const isMac = platform() === 'darwin';
|
|
10
|
+
const dmesgArgs = isMac ? [] : ['--time-format', 'iso'];
|
|
11
|
+
const output = await exec('dmesg', dmesgArgs);
|
|
12
|
+
return parseDmesgOutput(output, lines);
|
|
13
|
+
};
|
|
14
|
+
export function parseDmesgOutput(raw, lines) {
|
|
15
|
+
const allLines = raw.trim().split('\n').filter(Boolean);
|
|
16
|
+
const tailLines = allLines.slice(-lines);
|
|
17
|
+
return {
|
|
18
|
+
lines: tailLines,
|
|
19
|
+
lineCount: tailLines.length,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=logs-dmesg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-dmesg.js","sourceRoot":"","sources":["../../../src/system/probes/logs-dmesg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQnC;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAiB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EACxC,GAAG,CACJ,CAAC;IAEF,MAAM,KAAK,GAAG,QAAQ,EAAE,KAAK,QAAQ,CAAC;IACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IAExD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC9C,OAAO,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAC9B,GAAW,EACX,KAAa;IAEb,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAEzC,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,SAAS,CAAC,MAAM;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-dmesg.test.d.ts","sourceRoot":"","sources":["../../../src/system/probes/logs-dmesg.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { logsDmesg, parseDmesgOutput } from './logs-dmesg.js';
|
|
3
|
+
const DMESG_OUTPUT = `[2024-01-15T10:00:01+0000] EXT4-fs (sda1): mounted filesystem
|
|
4
|
+
[2024-01-15T10:00:02+0000] audit: type=1400 msg=avc:
|
|
5
|
+
[2024-01-15T10:00:03+0000] NET: Registered PF_INET6
|
|
6
|
+
[2024-01-15T10:00:04+0000] usb 1-1: new high-speed USB device
|
|
7
|
+
[2024-01-15T10:00:05+0000] e1000: Intel(R) PRO/1000 Network Driver`;
|
|
8
|
+
describe('parseDmesgOutput', () => {
|
|
9
|
+
it('returns last N lines', () => {
|
|
10
|
+
const result = parseDmesgOutput(DMESG_OUTPUT, 3);
|
|
11
|
+
expect(result.lineCount).toBe(3);
|
|
12
|
+
expect(result.lines).toHaveLength(3);
|
|
13
|
+
expect(result.lines[0]).toContain('NET: Registered PF_INET6');
|
|
14
|
+
expect(result.lines[2]).toContain('e1000');
|
|
15
|
+
});
|
|
16
|
+
it('returns all lines when lines exceeds total', () => {
|
|
17
|
+
const result = parseDmesgOutput(DMESG_OUTPUT, 100);
|
|
18
|
+
expect(result.lineCount).toBe(5);
|
|
19
|
+
expect(result.lines).toHaveLength(5);
|
|
20
|
+
});
|
|
21
|
+
it('handles empty output', () => {
|
|
22
|
+
const result = parseDmesgOutput('', 50);
|
|
23
|
+
expect(result.lineCount).toBe(0);
|
|
24
|
+
expect(result.lines).toHaveLength(0);
|
|
25
|
+
});
|
|
26
|
+
it('handles single line', () => {
|
|
27
|
+
const result = parseDmesgOutput('[0.000000] Linux version 6.1.0', 50);
|
|
28
|
+
expect(result.lineCount).toBe(1);
|
|
29
|
+
expect(result.lines[0]).toContain('Linux version');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('logsDmesg handler', () => {
|
|
33
|
+
it('passes correct args on Linux', async () => {
|
|
34
|
+
const calls = [];
|
|
35
|
+
const mockExec = async (cmd, args) => {
|
|
36
|
+
calls.push({ cmd, args });
|
|
37
|
+
return DMESG_OUTPUT;
|
|
38
|
+
};
|
|
39
|
+
const result = (await logsDmesg(undefined, mockExec));
|
|
40
|
+
expect(calls).toHaveLength(1);
|
|
41
|
+
expect(calls[0]?.cmd).toBe('dmesg');
|
|
42
|
+
// On the CI/test runner platform, args will vary
|
|
43
|
+
// but the handler should call dmesg
|
|
44
|
+
expect(result.lineCount).toBeGreaterThan(0);
|
|
45
|
+
});
|
|
46
|
+
it('clamps lines to valid range', async () => {
|
|
47
|
+
const mockExec = async () => DMESG_OUTPUT;
|
|
48
|
+
const result = (await logsDmesg({ lines: 2 }, mockExec));
|
|
49
|
+
expect(result.lineCount).toBe(2);
|
|
50
|
+
const result2 = (await logsDmesg({ lines: 9999 }, mockExec));
|
|
51
|
+
// 500 clamped but only 5 lines in fixture
|
|
52
|
+
expect(result2.lineCount).toBe(5);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=logs-dmesg.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-dmesg.test.js","sourceRoot":"","sources":["../../../src/system/probes/logs-dmesg.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProbeHandler } from '../../types.js';
|
|
2
|
+
export interface JournalEntry {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
priority: number;
|
|
5
|
+
message: string;
|
|
6
|
+
pid: number;
|
|
7
|
+
uid: number;
|
|
8
|
+
unit?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface JournalResult {
|
|
11
|
+
entries: JournalEntry[];
|
|
12
|
+
entryCount: number;
|
|
13
|
+
unit?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reads recent systemd journal entries via `journalctl -o json`.
|
|
17
|
+
* Linux only — fails with a clear message on macOS.
|
|
18
|
+
*/
|
|
19
|
+
export declare const logsJournal: ProbeHandler;
|
|
20
|
+
export declare function parseJournalOutput(raw: string, unit?: string): JournalResult;
|
|
21
|
+
//# sourceMappingURL=logs-journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-journal.d.ts","sourceRoot":"","sources":["../../../src/system/probes/logs-journal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,YA+BzB,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GACZ,aAAa,CAsCf"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { platform } from 'node:os';
|
|
2
|
+
/**
|
|
3
|
+
* Reads recent systemd journal entries via `journalctl -o json`.
|
|
4
|
+
* Linux only — fails with a clear message on macOS.
|
|
5
|
+
*/
|
|
6
|
+
export const logsJournal = async (params, exec) => {
|
|
7
|
+
if (platform() === 'darwin') {
|
|
8
|
+
throw new Error('system.logs.journal requires systemd (Linux only)');
|
|
9
|
+
}
|
|
10
|
+
const lines = Math.min(Math.max(Number(params?.lines ?? 50), 1), 500);
|
|
11
|
+
const unit = params?.unit;
|
|
12
|
+
const priority = params?.priority;
|
|
13
|
+
const args = [
|
|
14
|
+
'-n',
|
|
15
|
+
String(lines),
|
|
16
|
+
'--no-pager',
|
|
17
|
+
'-o',
|
|
18
|
+
'json',
|
|
19
|
+
];
|
|
20
|
+
if (unit) {
|
|
21
|
+
args.push('-u', unit);
|
|
22
|
+
}
|
|
23
|
+
if (priority) {
|
|
24
|
+
args.push('-p', priority);
|
|
25
|
+
}
|
|
26
|
+
const output = await exec('journalctl', args);
|
|
27
|
+
return parseJournalOutput(output, unit);
|
|
28
|
+
};
|
|
29
|
+
export function parseJournalOutput(raw, unit) {
|
|
30
|
+
const entries = [];
|
|
31
|
+
for (const line of raw.trim().split('\n')) {
|
|
32
|
+
if (!line)
|
|
33
|
+
continue;
|
|
34
|
+
let obj;
|
|
35
|
+
try {
|
|
36
|
+
obj = JSON.parse(line);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const timestamp = typeof obj.__REALTIME_TIMESTAMP === 'string'
|
|
42
|
+
? formatUsecTimestamp(obj.__REALTIME_TIMESTAMP)
|
|
43
|
+
: String(obj.__REALTIME_TIMESTAMP ?? '');
|
|
44
|
+
entries.push({
|
|
45
|
+
timestamp,
|
|
46
|
+
priority: Number(obj.PRIORITY ?? 6),
|
|
47
|
+
message: String(obj.MESSAGE ?? ''),
|
|
48
|
+
pid: Number(obj._PID ?? 0),
|
|
49
|
+
uid: Number(obj._UID ?? 0),
|
|
50
|
+
unit: obj._SYSTEMD_UNIT
|
|
51
|
+
? String(obj._SYSTEMD_UNIT)
|
|
52
|
+
: undefined,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const result = {
|
|
56
|
+
entries,
|
|
57
|
+
entryCount: entries.length,
|
|
58
|
+
};
|
|
59
|
+
if (unit) {
|
|
60
|
+
result.unit = unit;
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function formatUsecTimestamp(usec) {
|
|
65
|
+
const ms = Math.floor(Number(usec) / 1000);
|
|
66
|
+
if (Number.isNaN(ms))
|
|
67
|
+
return usec;
|
|
68
|
+
return new Date(ms).toISOString();
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=logs-journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-journal.js","sourceRoot":"","sources":["../../../src/system/probes/logs-journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-journal.test.d.ts","sourceRoot":"","sources":["../../../src/system/probes/logs-journal.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { logsJournal, parseJournalOutput } from './logs-journal.js';
|
|
3
|
+
vi.mock('node:os', () => ({ platform: () => 'linux' }));
|
|
4
|
+
const JOURNAL_JSON_OUTPUT = [
|
|
5
|
+
JSON.stringify({
|
|
6
|
+
__REALTIME_TIMESTAMP: '1700000000000000',
|
|
7
|
+
PRIORITY: '6',
|
|
8
|
+
MESSAGE: 'Started Session 42 of User root.',
|
|
9
|
+
_PID: '1',
|
|
10
|
+
_UID: '0',
|
|
11
|
+
_SYSTEMD_UNIT: 'session-42.scope',
|
|
12
|
+
}),
|
|
13
|
+
JSON.stringify({
|
|
14
|
+
__REALTIME_TIMESTAMP: '1700000001000000',
|
|
15
|
+
PRIORITY: '3',
|
|
16
|
+
MESSAGE: 'Failed to start nginx.service',
|
|
17
|
+
_PID: '512',
|
|
18
|
+
_UID: '0',
|
|
19
|
+
_SYSTEMD_UNIT: 'nginx.service',
|
|
20
|
+
}),
|
|
21
|
+
].join('\n');
|
|
22
|
+
const SINGLE_ENTRY = JSON.stringify({
|
|
23
|
+
__REALTIME_TIMESTAMP: '1700000000000000',
|
|
24
|
+
PRIORITY: '4',
|
|
25
|
+
MESSAGE: 'Warning from sshd',
|
|
26
|
+
_PID: '100',
|
|
27
|
+
_UID: '0',
|
|
28
|
+
});
|
|
29
|
+
describe('parseJournalOutput', () => {
|
|
30
|
+
it('parses multiple JSON journal entries', () => {
|
|
31
|
+
const result = parseJournalOutput(JOURNAL_JSON_OUTPUT);
|
|
32
|
+
expect(result.entries).toHaveLength(2);
|
|
33
|
+
expect(result.entryCount).toBe(2);
|
|
34
|
+
expect(result.unit).toBeUndefined();
|
|
35
|
+
expect(result.entries[0]).toEqual({
|
|
36
|
+
timestamp: '2023-11-14T22:13:20.000Z',
|
|
37
|
+
priority: 6,
|
|
38
|
+
message: 'Started Session 42 of User root.',
|
|
39
|
+
pid: 1,
|
|
40
|
+
uid: 0,
|
|
41
|
+
unit: 'session-42.scope',
|
|
42
|
+
});
|
|
43
|
+
expect(result.entries[1]).toEqual({
|
|
44
|
+
timestamp: '2023-11-14T22:13:21.000Z',
|
|
45
|
+
priority: 3,
|
|
46
|
+
message: 'Failed to start nginx.service',
|
|
47
|
+
pid: 512,
|
|
48
|
+
uid: 0,
|
|
49
|
+
unit: 'nginx.service',
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
it('sets unit in result when filtering by unit', () => {
|
|
53
|
+
const result = parseJournalOutput(SINGLE_ENTRY, 'sshd');
|
|
54
|
+
expect(result.unit).toBe('sshd');
|
|
55
|
+
expect(result.entries).toHaveLength(1);
|
|
56
|
+
});
|
|
57
|
+
it('skips malformed JSON lines', () => {
|
|
58
|
+
const input = `not json at all\n${SINGLE_ENTRY}\n{broken`;
|
|
59
|
+
const result = parseJournalOutput(input);
|
|
60
|
+
expect(result.entries).toHaveLength(1);
|
|
61
|
+
expect(result.entries[0]?.message).toBe('Warning from sshd');
|
|
62
|
+
});
|
|
63
|
+
it('handles empty output', () => {
|
|
64
|
+
const result = parseJournalOutput('');
|
|
65
|
+
expect(result.entries).toHaveLength(0);
|
|
66
|
+
expect(result.entryCount).toBe(0);
|
|
67
|
+
});
|
|
68
|
+
it('handles entry without _SYSTEMD_UNIT', () => {
|
|
69
|
+
const result = parseJournalOutput(SINGLE_ENTRY);
|
|
70
|
+
expect(result.entries[0]?.unit).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('logsJournal handler', () => {
|
|
74
|
+
it('passes correct args to exec with defaults', async () => {
|
|
75
|
+
const calls = [];
|
|
76
|
+
const mockExec = async (cmd, args) => {
|
|
77
|
+
calls.push({ cmd, args });
|
|
78
|
+
return SINGLE_ENTRY;
|
|
79
|
+
};
|
|
80
|
+
const result = (await logsJournal(undefined, mockExec));
|
|
81
|
+
expect(calls).toHaveLength(1);
|
|
82
|
+
expect(calls[0]?.cmd).toBe('journalctl');
|
|
83
|
+
expect(calls[0]?.args).toEqual([
|
|
84
|
+
'-n', '50', '--no-pager', '-o', 'json',
|
|
85
|
+
]);
|
|
86
|
+
expect(result.entryCount).toBe(1);
|
|
87
|
+
});
|
|
88
|
+
it('passes unit and priority params', async () => {
|
|
89
|
+
const calls = [];
|
|
90
|
+
const mockExec = async (cmd, args) => {
|
|
91
|
+
calls.push({ cmd, args });
|
|
92
|
+
return SINGLE_ENTRY;
|
|
93
|
+
};
|
|
94
|
+
await logsJournal({ unit: 'nginx', priority: 'err', lines: 100 }, mockExec);
|
|
95
|
+
expect(calls[0]?.args).toEqual([
|
|
96
|
+
'-n', '100', '--no-pager', '-o', 'json',
|
|
97
|
+
'-u', 'nginx',
|
|
98
|
+
'-p', 'err',
|
|
99
|
+
]);
|
|
100
|
+
});
|
|
101
|
+
it('clamps lines to valid range', async () => {
|
|
102
|
+
const calls = [];
|
|
103
|
+
const mockExec = async (cmd, args) => {
|
|
104
|
+
calls.push({ cmd, args });
|
|
105
|
+
return SINGLE_ENTRY;
|
|
106
|
+
};
|
|
107
|
+
await logsJournal({ lines: 9999 }, mockExec);
|
|
108
|
+
expect(calls[0]?.args).toContain('500');
|
|
109
|
+
await logsJournal({ lines: 0 }, mockExec);
|
|
110
|
+
expect(calls[1]?.args).toContain('1');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
//# sourceMappingURL=logs-journal.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-journal.test.js","sourceRoot":"","sources":["../../../src/system/probes/logs-journal.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ProbeHandler } from '../../types.js';
|
|
2
|
+
export interface LogTailResult {
|
|
3
|
+
logPath: string;
|
|
4
|
+
lines: string[];
|
|
5
|
+
lineCount: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function validateLogPath(path: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Tails a log file at a given absolute path.
|
|
10
|
+
* Restricted to /var/log/ and /tmp/ for security.
|
|
11
|
+
*/
|
|
12
|
+
export declare const logsTail: ProbeHandler;
|
|
13
|
+
export declare function parseLogTailOutput(raw: string, logPath: string): LogTailResult;
|
|
14
|
+
//# sourceMappingURL=logs-tail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-tail.d.ts","sourceRoot":"","sources":["../../../src/system/probes/logs-tail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAqBlD;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,YAoBtB,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,aAAa,CAOf"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const ALLOWED_PREFIXES = ['/var/log/', '/tmp/'];
|
|
2
|
+
export function validateLogPath(path) {
|
|
3
|
+
if (!path.startsWith('/')) {
|
|
4
|
+
throw new Error(`Path must be absolute (start with /): ${path}`);
|
|
5
|
+
}
|
|
6
|
+
if (path.includes('..')) {
|
|
7
|
+
throw new Error(`Path must not contain '..': ${path}`);
|
|
8
|
+
}
|
|
9
|
+
const allowed = ALLOWED_PREFIXES.some((prefix) => path.startsWith(prefix));
|
|
10
|
+
if (!allowed) {
|
|
11
|
+
throw new Error(`Path must start with one of: ${ALLOWED_PREFIXES.join(', ')} — got: ${path}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Tails a log file at a given absolute path.
|
|
16
|
+
* Restricted to /var/log/ and /tmp/ for security.
|
|
17
|
+
*/
|
|
18
|
+
export const logsTail = async (params, exec) => {
|
|
19
|
+
const path = params?.path;
|
|
20
|
+
if (!path) {
|
|
21
|
+
throw new Error('Missing required parameter: path');
|
|
22
|
+
}
|
|
23
|
+
validateLogPath(path);
|
|
24
|
+
const lines = Math.min(Math.max(Number(params?.lines ?? 50), 1), 500);
|
|
25
|
+
const output = await exec('tail', [
|
|
26
|
+
'-n',
|
|
27
|
+
String(lines),
|
|
28
|
+
path,
|
|
29
|
+
]);
|
|
30
|
+
return parseLogTailOutput(output, path);
|
|
31
|
+
};
|
|
32
|
+
export function parseLogTailOutput(raw, logPath) {
|
|
33
|
+
const lines = raw.split('\n').filter(Boolean);
|
|
34
|
+
return {
|
|
35
|
+
logPath,
|
|
36
|
+
lines,
|
|
37
|
+
lineCount: lines.length,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=logs-tail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-tail.js","sourceRoot":"","sources":["../../../src/system/probes/logs-tail.ts"],"names":[],"mappings":"AAQA,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAEhD,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,yCAAyC,IAAI,EAAE,CAChD,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,+BAA+B,IAAI,EAAE,CACtC,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAC/C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CACxB,CAAC;IACF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAiB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAC3D,MAAM,IAAI,GAAG,MAAM,EAAE,IAA0B,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,eAAe,CAAC,IAAI,CAAC,CAAC;IAEtB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EACxC,GAAG,CACJ,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;QAChC,IAAI;QACJ,MAAM,CAAC,KAAK,CAAC;QACb,IAAI;KACL,CAAC,CAAC;IAEH,OAAO,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,OAAe;IAEf,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9C,OAAO;QACL,OAAO;QACP,KAAK;QACL,SAAS,EAAE,KAAK,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-tail.test.d.ts","sourceRoot":"","sources":["../../../src/system/probes/logs-tail.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { logsTail, parseLogTailOutput, validateLogPath, } from './logs-tail.js';
|
|
3
|
+
const SYSLOG_OUTPUT = `Jan 15 10:00:01 host systemd[1]: Started Session 1
|
|
4
|
+
Jan 15 10:00:02 host sshd[512]: Accepted publickey
|
|
5
|
+
Jan 15 10:00:03 host kernel: audit: type=1400`;
|
|
6
|
+
describe('validateLogPath', () => {
|
|
7
|
+
it('accepts valid /var/log/ paths', () => {
|
|
8
|
+
expect(() => validateLogPath('/var/log/syslog')).not.toThrow();
|
|
9
|
+
expect(() => validateLogPath('/var/log/nginx/access.log')).not.toThrow();
|
|
10
|
+
});
|
|
11
|
+
it('accepts valid /tmp/ paths', () => {
|
|
12
|
+
expect(() => validateLogPath('/tmp/debug.log')).not.toThrow();
|
|
13
|
+
});
|
|
14
|
+
it('rejects relative paths', () => {
|
|
15
|
+
expect(() => validateLogPath('var/log/syslog')).toThrow('Path must be absolute');
|
|
16
|
+
});
|
|
17
|
+
it('rejects paths with ..', () => {
|
|
18
|
+
expect(() => validateLogPath('/var/log/../../etc/shadow')).toThrow("must not contain '..'");
|
|
19
|
+
});
|
|
20
|
+
it('rejects paths outside allowed prefixes', () => {
|
|
21
|
+
expect(() => validateLogPath('/etc/shadow')).toThrow('must start with one of');
|
|
22
|
+
expect(() => validateLogPath('/home/user/.bash_history')).toThrow('must start with one of');
|
|
23
|
+
expect(() => validateLogPath('/root/.ssh/id_rsa')).toThrow('must start with one of');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe('parseLogTailOutput', () => {
|
|
27
|
+
it('parses multi-line log output', () => {
|
|
28
|
+
const result = parseLogTailOutput(SYSLOG_OUTPUT, '/var/log/syslog');
|
|
29
|
+
expect(result.logPath).toBe('/var/log/syslog');
|
|
30
|
+
expect(result.lineCount).toBe(3);
|
|
31
|
+
expect(result.lines[0]).toContain('Started Session');
|
|
32
|
+
expect(result.lines[2]).toContain('audit');
|
|
33
|
+
});
|
|
34
|
+
it('handles empty output', () => {
|
|
35
|
+
const result = parseLogTailOutput('', '/var/log/empty.log');
|
|
36
|
+
expect(result.lineCount).toBe(0);
|
|
37
|
+
expect(result.lines).toHaveLength(0);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('logsTail handler', () => {
|
|
41
|
+
it('throws when path is missing', async () => {
|
|
42
|
+
const mockExec = async () => '';
|
|
43
|
+
await expect(logsTail(undefined, mockExec)).rejects.toThrow('Missing required parameter: path');
|
|
44
|
+
await expect(logsTail({}, mockExec)).rejects.toThrow('Missing required parameter: path');
|
|
45
|
+
});
|
|
46
|
+
it('throws for invalid paths before calling exec', async () => {
|
|
47
|
+
const calls = [];
|
|
48
|
+
const mockExec = async (cmd) => {
|
|
49
|
+
calls.push(cmd);
|
|
50
|
+
return '';
|
|
51
|
+
};
|
|
52
|
+
await expect(logsTail({ path: '/etc/shadow' }, mockExec)).rejects.toThrow('must start with one of');
|
|
53
|
+
expect(calls).toHaveLength(0);
|
|
54
|
+
});
|
|
55
|
+
it('passes correct args with defaults', async () => {
|
|
56
|
+
const calls = [];
|
|
57
|
+
const mockExec = async (cmd, args) => {
|
|
58
|
+
calls.push({ cmd, args });
|
|
59
|
+
return SYSLOG_OUTPUT;
|
|
60
|
+
};
|
|
61
|
+
const result = (await logsTail({ path: '/var/log/syslog' }, mockExec));
|
|
62
|
+
expect(calls).toHaveLength(1);
|
|
63
|
+
expect(calls[0]?.cmd).toBe('tail');
|
|
64
|
+
expect(calls[0]?.args).toEqual([
|
|
65
|
+
'-n', '50', '/var/log/syslog',
|
|
66
|
+
]);
|
|
67
|
+
expect(result.logPath).toBe('/var/log/syslog');
|
|
68
|
+
expect(result.lineCount).toBe(3);
|
|
69
|
+
});
|
|
70
|
+
it('clamps lines to valid range', async () => {
|
|
71
|
+
const calls = [];
|
|
72
|
+
const mockExec = async (cmd, args) => {
|
|
73
|
+
calls.push({ cmd, args });
|
|
74
|
+
return '';
|
|
75
|
+
};
|
|
76
|
+
await logsTail({ path: '/var/log/syslog', lines: 9999 }, mockExec);
|
|
77
|
+
expect(calls[0]?.args).toContain('500');
|
|
78
|
+
await logsTail({ path: '/var/log/syslog', lines: 0 }, mockExec);
|
|
79
|
+
expect(calls[1]?.args).toContain('1');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=logs-tail.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-tail.test.js","sourceRoot":"","sources":["../../../src/system/probes/logs-tail.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ProbeHandler } from '../../types.js';
|
|
2
|
+
export interface TracerouteHop {
|
|
3
|
+
hop: number;
|
|
4
|
+
ip: string | null;
|
|
5
|
+
rttMs: (number | null)[];
|
|
6
|
+
}
|
|
7
|
+
export interface TracerouteResult {
|
|
8
|
+
host: string;
|
|
9
|
+
hops: TracerouteHop[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Traces the network path to a host via `traceroute -n`.
|
|
13
|
+
* Works on both Linux and macOS.
|
|
14
|
+
*/
|
|
15
|
+
export declare const traceroute: ProbeHandler;
|
|
16
|
+
export declare function parseTracerouteOutput(raw: string, host: string): TracerouteResult;
|
|
17
|
+
//# sourceMappingURL=traceroute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceroute.d.ts","sourceRoot":"","sources":["../../../src/system/probes/traceroute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,YAqBxB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,gBAAgB,CAuBlB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traces the network path to a host via `traceroute -n`.
|
|
3
|
+
* Works on both Linux and macOS.
|
|
4
|
+
*/
|
|
5
|
+
export const traceroute = async (params, exec) => {
|
|
6
|
+
const host = params?.host;
|
|
7
|
+
if (!host) {
|
|
8
|
+
throw new Error('Missing required parameter: host');
|
|
9
|
+
}
|
|
10
|
+
const maxHops = Math.min(Math.max(Number(params?.maxHops ?? 30), 1), 64);
|
|
11
|
+
const output = await exec('traceroute', [
|
|
12
|
+
'-n',
|
|
13
|
+
'-m',
|
|
14
|
+
String(maxHops),
|
|
15
|
+
'-w',
|
|
16
|
+
'2',
|
|
17
|
+
host,
|
|
18
|
+
]);
|
|
19
|
+
return parseTracerouteOutput(output, host);
|
|
20
|
+
};
|
|
21
|
+
export function parseTracerouteOutput(raw, host) {
|
|
22
|
+
const hops = [];
|
|
23
|
+
const lines = raw.trim().split('\n');
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
// Skip the header line ("traceroute to ...")
|
|
26
|
+
const hopMatch = line.match(/^\s*(\d+)\s+(.+)/);
|
|
27
|
+
if (!hopMatch)
|
|
28
|
+
continue;
|
|
29
|
+
const hopNum = Number(hopMatch[1]);
|
|
30
|
+
const rest = hopMatch[2] ?? '';
|
|
31
|
+
// All probes timed out: "* * *"
|
|
32
|
+
if (/^\*\s+\*\s+\*\s*$/.test(rest)) {
|
|
33
|
+
hops.push({ hop: hopNum, ip: null, rttMs: [null, null, null] });
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const hop = parseHopLine(hopNum, rest);
|
|
37
|
+
hops.push(hop);
|
|
38
|
+
}
|
|
39
|
+
return { host, hops };
|
|
40
|
+
}
|
|
41
|
+
function parseHopLine(hopNum, rest) {
|
|
42
|
+
let ip = null;
|
|
43
|
+
const rttMs = [];
|
|
44
|
+
// Tokenize the rest of the line
|
|
45
|
+
const tokens = rest.trim().split(/\s+/);
|
|
46
|
+
let i = 0;
|
|
47
|
+
while (i < tokens.length) {
|
|
48
|
+
const token = tokens[i];
|
|
49
|
+
if (!token || token === '*') {
|
|
50
|
+
rttMs.push(null);
|
|
51
|
+
i++;
|
|
52
|
+
}
|
|
53
|
+
else if (token === 'ms') {
|
|
54
|
+
// Skip "ms" — already consumed the number
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
else if (/^\d+\.\d+\.\d+\.\d+$/.test(token) || token.includes(':')) {
|
|
58
|
+
// IPv4 or IPv6 address
|
|
59
|
+
ip = token;
|
|
60
|
+
i++;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const num = Number.parseFloat(token);
|
|
64
|
+
if (!Number.isNaN(num)) {
|
|
65
|
+
rttMs.push(num);
|
|
66
|
+
}
|
|
67
|
+
i++;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { hop: hopNum, ip, rttMs };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=traceroute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceroute.js","sourceRoot":"","sources":["../../../src/system/probes/traceroute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceroute.test.d.ts","sourceRoot":"","sources":["../../../src/system/probes/traceroute.test.ts"],"names":[],"mappings":""}
|