carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package hostbox
4
5import (
6 "context"
7 "errors"
8 "os"
9 "path/filepath"
10 "testing"
11 "time"
12)
13
14func TestPlan9JournalMigrationDurableAndNeverReimportsLegacy(t *testing.T) {
15 s, _, in := journalFixture(t)
16 legacy := t.TempDir()
17 old, err := OpenLaunchJournal(filepath.Join(legacy, "launches.db"))
18 if err != nil {
19 t.Fatal(err)
20 }
21 if err = old.Create(t.Context(), in); err != nil {
22 t.Fatal(err)
23 }
24 if err = old.Close(); err != nil {
25 t.Fatal(err)
26 }
27 inventory, err := OpenStopInventoryDB(filepath.Join(legacy, "inventory.db"))
28 if err != nil {
29 t.Fatal(err)
30 }
31 if err = inventory.WriteStopInventory(t.Context(), StopInventory{Complete: true, Host: in.Target.Host, Incarnation: "inc", InstallationStamp: 1, Box: "box", Enrollment: "enrollment", DirectoryRevision: "1"}); err != nil {
32 t.Fatal(err)
33 }
34 inventory.Close()
35 if err = s.MigrateLegacy(t.Context(), legacy, "box", "enrollment", nil, nil); err == nil {
36 t.Fatal("unquiesced import accepted")
37 }
38 released := false
39 freeze := func(context.Context) (func(), error) { return func() { released = true }, nil }
40 if err = s.MigrateLegacy(t.Context(), legacy, "box", "enrollment", freeze, nil); !errors.Is(err, ErrLegacyJournalProof) {
41 t.Fatalf("unproven legacy history: %v", err)
42 }
43 if got, err := s.Launches.HasHost(t.Context(), in.Target.Host); err != nil || got {
44 t.Fatalf("unproven history committed: %v %v", got, err)
45 }
46 if err = s.MigrateLegacy(t.Context(), legacy, "box", "enrollment", freeze, func(ctx context.Context, _ LaunchInventory, _ StopInventory, _ StopKernelJournal) error {
47 if deadline, ok := ctx.Deadline(); !ok || time.Until(deadline) > 120*time.Second {
48 t.Fatal("unbounded proof context")
49 }
50 if s.Launches.db.Stats().InUse != 0 {
51 t.Fatal("proof runs with root SQLite connection held")
52 }
53 probe, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
54 defer cancel()
55 var one int
56 return s.Launches.db.QueryRowContext(probe, "SELECT 1").Scan(&one)
57 }); err != nil {
58 t.Fatal(err)
59 }
60 if !released {
61 t.Fatal("quiescence not released")
62 }
63 if _, err = s.Launches.Read(t.Context(), in.Target); err != nil {
64 t.Fatal(err)
65 }
66 if _, err = s.Inventory.ReadExactStopInventory(t.Context(), in.Target); err != nil {
67 t.Fatal(err)
68 }
69 // Root can continue writing. A stale legacy snapshot is never replayed.
70 if err = s.Launches.RecordProducer(t.Context(), in.Target, "new-producer"); err != nil {
71 t.Fatal(err)
72 }
73 if err = s.MigrateLegacy(t.Context(), legacy, "box", "enrollment", nil, nil); err != nil {
74 t.Fatal(err)
75 }
76 got, err := s.Launches.Read(t.Context(), in.Target)
77 if err != nil || len(got.ProducerIDs) != 1 {
78 t.Fatalf("stale import: %+v %v", got, err)
79 }
80 if _, err = os.Stat(filepath.Join(legacy, "launches.db")); err != nil {
81 t.Fatal("legacy evidence removed", err)
82 }
83}
84func TestPlan9JournalMigrationRejectsLinksAndRollsBackBothTables(t *testing.T) {
85 s, _, in := journalFixture(t)
86 legacy := t.TempDir()
87 old, err := OpenLaunchJournal(filepath.Join(legacy, "launches.db"))
88 if err != nil {
89 t.Fatal(err)
90 }
91 if err = old.Create(t.Context(), in); err != nil {
92 t.Fatal(err)
93 }
94 old.Close()
95 victim := filepath.Join(t.TempDir(), "victim")
96 if err = os.WriteFile(victim, []byte("unaltered"), 0600); err != nil {
97 t.Fatal(err)
98 }
99 if err = os.Symlink(victim, filepath.Join(legacy, "inventory.db")); err != nil {
100 t.Fatal(err)
101 }
102 freeze := func(context.Context) (func(), error) { return func() {}, nil }
103 if err = s.MigrateLegacy(t.Context(), legacy, "box", "enrollment", freeze, func(context.Context, LaunchInventory, StopInventory, StopKernelJournal) error { return nil }); err == nil {
104 t.Fatal("symlink import accepted")
105 }
106 if got, err := s.Launches.HasHost(t.Context(), in.Target.Host); err != nil || got {
107 t.Fatalf("partial migration: %v %v", got, err)
108 }
109 raw, err := os.ReadFile(victim)
110 if err != nil || string(raw) != "unaltered" {
111 t.Fatal("victim changed", err)
112 }
113 if err = os.Remove(filepath.Join(legacy, "inventory.db")); err != nil {
114 t.Fatal(err)
115 }
116 if err = os.Link(victim, filepath.Join(legacy, "inventory.db")); err != nil {
117 t.Fatal(err)
118 }
119 if err = s.MigrateLegacy(t.Context(), legacy, "box", "enrollment", freeze, func(context.Context, LaunchInventory, StopInventory, StopKernelJournal) error { return nil }); err == nil {
120 t.Fatal("hardlink import accepted")
121 }
122 if _, err = os.Stat(victim); errors.Is(err, os.ErrNotExist) {
123 t.Fatal("victim removed")
124 }
125}
126