systemd: serve kernel-log, the kernel's messages of one boot (issue 1975)

journalctl --dmesg --boot=N under the same escalation, window, priority, fixed-string match, 2000-line cap
and redaction as the journal verb (shapeLines is the one filter both use); a boot is 0 or a negative whole
number, refused otherwise before anything runs. No scope: the kernel belongs to no manager.

Builds: issue 1975, the operator's request of 2026-11-12 (the lead's handover; no design line names the verb)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 02:17:28 +01:00
parent d9f2b7bcfa
commit 3ebcb15a4b
6 changed files with 190 additions and 27 deletions
@@ -241,3 +241,75 @@ func TestFailedIsOnTheSeatAndNarrowsToAScope(t *testing.T) {
t.Fatal("a scope that is none was accepted")
}
}
// The kernel-log verb (issue 1975): the kernel's messages of one boot, in the journal verb's window, priority,
// match, cap and redaction, and a boot named 0, -1, and so on.
func TestTheKernelLogIsOneBootsMessagesInTheJournalsForms(t *testing.T) {
var calls []call
m := journalOf([]string{"2026-11-12T10:00:00+0100 host kernel: usb 1-1: new device"}, "", &calls)
got, err := m.KernelLog(JournalQuery{Lines: 50, Since: "-2h", Priority: "err", Boot: "-1"})
if err != nil {
t.Fatal(err)
}
want := "--no-pager --output=short-iso --dmesg --boot=-1 --since=-2h --priority=3 --lines=50"
if a := strings.Join(journalArgs(t, calls), " "); a != want {
t.Fatalf("journalctl was given\n %s\nnot\n %s", a, want)
}
if calls[0].cmd != "sudo" || got["boot"] != "-1" || got["count"] != 1 {
t.Fatalf("not escalated, or the answer is wrong: %+v %+v", calls[0], got)
}
calls = nil
if _, err := m.KernelLog(JournalQuery{}); err != nil {
t.Fatal(err)
}
if a := strings.Join(journalArgs(t, calls), " "); a != "--no-pager --output=short-iso --dmesg --boot=0 --lines=100" {
t.Fatalf("the default is this boot and a hundred lines: %s", a)
}
// Arguments arrive as the seat's strings or as numbers.
for _, a := range []map[string]any{{"boot": float64(-2)}, {"boot": "-2"}} {
q, err := journalQuery(a)
if err != nil || q.Boot != "-2" {
t.Errorf("%v: %+v %v", a, q, err)
}
}
}
func TestAKernelLogBootIsRefusedBeforeAnythingRunsUnlessItIsZeroOrBefore(t *testing.T) {
for _, bad := range []string{"1", "abc", "--user", "-1 --merge", "-10000", "0x1", "-1;id"} {
var calls []call
m := journalOf(nil, "", &calls)
if _, err := m.KernelLog(JournalQuery{Boot: bad}); err == nil {
t.Errorf("boot %q accepted", bad)
}
if len(calls) != 0 {
t.Errorf("boot %q reached journalctl: %v", bad, calls)
}
}
}
func TestTheKernelLogKeepsTheCapTheMatchAndTheRedaction(t *testing.T) {
var calls []call
m := journalOf([]string{"k one", "k password=hunter2secretvalue here", "k two"}, "", &calls)
got, err := m.KernelLog(JournalQuery{Match: "k t", Lines: 5000})
if err != nil {
t.Fatal(err)
}
if a := strings.Join(journalArgs(t, calls), " "); !strings.HasSuffix(a, fmt.Sprintf("--lines=%d", MatchScan)) {
t.Errorf("a match scans the window's last %d lines: %s", MatchScan, a)
}
if lines := got["lines"].([]string); len(lines) != 1 || lines[0] != "k two" {
t.Errorf("the match kept %v", lines)
}
calls = nil
m = journalOf([]string{"k password=hunter2secretvalue here"}, "", &calls)
got, err = m.KernelLog(JournalQuery{Lines: 5000})
if err != nil {
t.Fatal(err)
}
if a := strings.Join(journalArgs(t, calls), " "); !strings.HasSuffix(a, "--lines=2000") {
t.Errorf("the cap is 2000: %s", a)
}
if strings.Contains(fmt.Sprint(got["lines"]), "hunter2") || got["redacted"] == nil {
t.Errorf("a secret in a kernel line was answered: %v", got)
}
}