aboutsummaryrefslogtreecommitdiff
path: root/internal/journal
diff options
context:
space:
mode:
Diffstat (limited to 'internal/journal')
-rw-r--r--internal/journal/read.go6
-rw-r--r--internal/journal/read_test.go29
2 files changed, 33 insertions, 2 deletions
diff --git a/internal/journal/read.go b/internal/journal/read.go
index 48cd6b0..9099c0d 100644
--- a/internal/journal/read.go
+++ b/internal/journal/read.go
@@ -172,10 +172,12 @@ func Entries(path, runID string) ([]Entry, error) {
// runFieldOf best-effort extracts a line's Run column even when the line
// otherwise fails to parse, so Entries can tell whether an unparsable line
-// belonged to the run it was asked for.
+// belonged to the run it was asked for. The column counts only when a tab
+// ends it: a line cut inside it holds a prefix of some run's ID, which names
+// no run (plan 10 re-check R2).
func runFieldOf(line string) (string, bool) {
f := strings.SplitN(line, "\t", 3)
- if len(f) < 2 {
+ if len(f) < 3 {
return "", false
}
return unescape(f[1]), true
diff --git a/internal/journal/read_test.go b/internal/journal/read_test.go
index fb6f77f..676b2bd 100644
--- a/internal/journal/read_test.go
+++ b/internal/journal/read_test.go
@@ -702,3 +702,32 @@ func TestReversedStepsCountsEveryUndoOfARun(t *testing.T) {
}
}
}
+
+// TestEntriesRefusesALineCutInsideItsRunColumn: a crash that cuts the last
+// line inside its run column leaves a prefix of some run's ID - it cannot
+// be called another run's line, so inside this run's window it refuses the
+// run (plan 10 re-check R2).
+func TestEntriesRefusesALineCutInsideItsRunColumn(t *testing.T) {
+ path := filepath.Join(t.TempDir(), "krino.log")
+ w, _ := Open(path)
+ at := time.Date(2026, 9, 11, 10, 2, 3, 0, time.UTC)
+ run := "20260911T100203-ab12"
+ for _, e := range []Entry{
+ {Time: at, Run: run, Action: "run-start", Status: "ok"},
+ {Time: at, Run: run, Dir: "dl", File: "x.pdf", Step: 1, Action: "copy", Status: "ok", Src: "/a/x.pdf", Dst: "/b/x.pdf"},
+ } {
+ if err := w.Append(e); err != nil {
+ t.Fatal(err)
+ }
+ }
+ w.Close()
+ f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.WriteString("2026-09-11T10:02:04Z\t20260911T10")
+ f.Close()
+ if got, err := Entries(path, run); err == nil {
+ t.Errorf("Entries = %+v, no error; a line cut inside its run column must refuse the run", got)
+ }
+}