carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5 "encoding/json"
6 "os"
7 "path/filepath"
8 "testing"
9 "time"
10
11 "github.com/carlosframework/platform/internal/hostbox"
12 "github.com/carlosframework/platform/internal/hostclaim"
13 "github.com/carlosframework/platform/internal/hostevidence"
14 "github.com/carlosframework/platform/internal/hostguard"
15 "github.com/carlosframework/platform/internal/hostops"
16 "github.com/carlosframework/platform/internal/provision"
17 "github.com/carlosframework/platform/internal/registry"
18 "github.com/carlosframework/platform/internal/release"
19 "golang.org/x/sys/unix"
20)
21
22func migrationHistoricFixture(t *testing.T, store release.Store, r ClaimRuntimeResources, owners ClaimOwnerBindings, actor hostbox.Actor, plan *hostops.BackfillPlan) (hostguard.FenceTarget, []byte) {
23 t.Helper()
24 ctx := t.Context()
25 at := time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC)
26 rec := provision.Record{Schema: 1, Host: "historic.example", Account: "bab", App: "app", Channel: "stable", Region: "ie", CreatedAt: at}
27 raw, _ := json.Marshal(rec)
28 key := provision.RecordKey(rec.Account, rec.App, rec.Host)
29 tag, err := store.Put(ctx, key, raw, "")
30 if err != nil {
31 t.Fatal(err)
32 }
33 plan.Hosts[rec.Host] = hostops.BackfillHost{Key: key, ETag: tag}
34 inc, err := hostclaim.Incarnation(rec.Account, rec.App, rec.Host, at)
35 if err != nil {
36 t.Fatal(err)
37 }
38 claim := hostclaim.Claim{V: 2, Host: rec.Host, Gen: 1, Holder: &hostclaim.Holder{Family: "instance", Key: key, Account: rec.Account, App: rec.App, CreatedAt: at, Incarnation: inc, Location: "instances/" + rec.Host, Generation: "generation", Stamp: 1, Session: 9, WriterBox: actor.Box, Admissions: []hostclaim.AdmissionRecord{{Region: "ie", Session: 9, Box: actor.Box, Generation: "generation", Mode: "cold", Covered: true}}}, Op: hostclaim.Op{Kind: hostclaim.KindServing, Exec: actor.Box, Participants: []string{actor.Box}}}
39 raw, _ = json.Marshal(claim)
40 ckey, _ := hostclaim.Key(rec.Host)
41 ctag, err := store.Put(ctx, ckey, raw, "")
42 if err != nil {
43 t.Fatal(err)
44 }
45 if _, err := hostclaim.Read(ctx, store, rec.Host); err != nil {
46 t.Fatal("claim fixture", err)
47 }
48 target := hostguard.FenceTarget{Host: rec.Host, Incarnation: inc, Stamp: 1, Session: 9, Box: actor.Box, Enrollment: actor.Enrollment, Region: "ie", DirectoryRevision: "1", BootID: "historic-boot", ControllerID: "historic-controller", ClaimGen: 1, ClaimETag: ctag, FenceID: "historic-fence"}
49 if err := r.Registry.UpsertTimer(registry.Timer{Host: rec.Host, Name: "refresh", Kind: "cron", Spec: "0 0 * * *", Path: "/refresh"}); err != nil {
50 t.Fatal(err)
51 }
52 legacy := filepath.Join(r.DataDir, ".hostclaims")
53 launches, err := hostbox.OpenLaunchJournal(filepath.Join(legacy, "launches.db"))
54 if err != nil {
55 t.Fatal(err)
56 }
57 launch := hostbox.LaunchInventory{Target: target, ControllerPID: 999999, ProcessStart: "1", NoState: true, Groups: []hostbox.LaunchGroup{{RelativePath: "historic-session", Device: 1, Inode: 2}}}
58 if err := launches.Create(ctx, launch); err != nil {
59 t.Fatal(err)
60 }
61 if err := launches.CloseWriters(ctx, target); err != nil {
62 t.Fatal(err)
63 }
64 journal, err := launches.ReadStopKernelJournal(ctx, target)
65 if err != nil {
66 t.Fatal(err)
67 }
68 if err := launches.Close(); err != nil {
69 t.Fatal(err)
70 }
71 path := filepath.Join(r.DataDir, "historic-data")
72 if err := os.WriteFile(path, []byte("retained tenant bytes"), 0600); err != nil {
73 t.Fatal(err)
74 }
75 var st unix.Stat_t
76 if err := unix.Lstat(path, &st); err != nil {
77 t.Fatal(err)
78 }
79 in := hostbox.StopInventory{Complete: true, Host: rec.Host, Incarnation: inc, InstallationStamp: 1, Box: actor.Box, Enrollment: actor.Enrollment, DirectoryRevision: "1", Entries: []hostbox.StopInventoryEntry{{Kind: "path", ArtifactID: "historic-data", ManagedRoot: "data", RelativePath: "historic-data", Ownership: "historic-owner", Materialization: "materialized", Device: uint64(st.Dev), Inode: st.Ino, Type: st.Mode & unix.S_IFMT}, {Kind: "timer", ArtifactID: "timer", ManagedRoot: "timers", RelativePath: rec.Host + "/refresh", Ownership: "historic-owner", Materialization: "materialized"}}}
80 in.Entries[0].Identity = testPersistentInventory(t, path)
81 inventory, err := openLegacyInventory(t, filepath.Join(legacy, "inventory.db"))
82 if err != nil {
83 t.Fatal(err)
84 }
85 if err := inventory.WriteStopInventory(ctx, in); err != nil {
86 t.Fatal(err)
87 }
88 if err := inventory.Close(); err != nil {
89 t.Fatal(err)
90 }
91 receipt := StopReceipt{V: 1, ID: "historic-stop", Kind: "stopped", Host: target.Host, Incarnation: inc, InstallationStamp: 1, WriterSession: 9, Box: actor.Box, Enrollment: actor.Enrollment, Region: "ie", BootID: target.BootID, ObservedBootID: target.BootID, ControllerID: target.ControllerID, DirectoryRevision: "1", Binding: "1", ClaimGen: 1, ClaimETag: ctag, FenceID: target.FenceID, EvidenceAt: at, RequestLimitNS: int64(hostbox.RequestLimit), InventorySHA256: digestStop(in), LocalJournalSHA256: digestStop(journal), CgroupIdentities: []string{"historic-session"}}
92 raw, _ = json.Marshal(receipt)
93 if err := hostevidence.Publish(ctx, store, owners.EvidenceKey, stopEvidenceKey(target.Host, "", actor.Box, receipt.ID), raw); err != nil {
94 t.Fatal(err)
95 }
96 return target, raw
97}
98
99func TestPlan14RootMigrationHistoricEvidence(t *testing.T) {
100 store, r, owners, _ := fix4JournalFixture(t)
101 actor, err := owners.Identity.Verify(t.Context())
102 if err != nil {
103 t.Fatal(err)
104 }
105 plan := hostops.BackfillPlan{Hosts: map[string]hostops.BackfillHost{}}
106 target, raw := migrationHistoricFixture(t, store, r, owners.ClaimOwnerBindings, actor, &plan)
107 j, err := hostbox.OpenLaunchJournal(filepath.Join(t.TempDir(), "root.db"))
108 if err != nil {
109 t.Fatal(err)
110 }
111 defer j.Close()
112 service, err := hostbox.NewJournalService(j)
113 if err != nil {
114 t.Fatal(err)
115 }
116 if err := service.MigrateLegacy(t.Context(), filepath.Join(r.DataDir, ".hostclaims"), actor.Box, actor.Enrollment, func(context.Context) (func(), error) { return func() {}, nil }, legacyJournalProof(store, owners.RetirementAuthority.Directory)); err != nil {
117 t.Fatal("signed legacy import", err)
118 }
119 launch, err := j.Read(t.Context(), target)
120 if err != nil {
121 t.Fatal(err)
122 }
123 result, err := readMigrationStop(t.Context(), store, owners.RetirementAuthority.Directory, j, service.Inventory, launch)
124 if err != nil || string(result.Bytes) != string(raw) {
125 t.Fatal("exact historic evidence", err)
126 }
127 signatureKey := result.Key + ".sig"
128 validSignature, signatureETag, err := store.Get(t.Context(), signatureKey)
129 if err != nil {
130 t.Fatal(err)
131 }
132 badETag, err := store.Put(t.Context(), signatureKey, []byte("forged"), signatureETag)
133 if err != nil {
134 t.Fatal(err)
135 }
136 if _, err := readMigrationStop(t.Context(), store, owners.RetirementAuthority.Directory, j, service.Inventory, launch); err == nil {
137 t.Fatal("forged historic signature accepted")
138 }
139 if _, err := store.Put(t.Context(), signatureKey, validSignature, badETag); err != nil {
140 t.Fatal(err)
141 }
142 if _, err := readMigrationStop(t.Context(), store, owners.RetirementAuthority.Directory, j, service.Inventory, launch); err != nil {
143 t.Fatal("valid evidence after refusal", err)
144 }
145 launch.Target.Session++
146 if _, err := readMigrationStop(t.Context(), store, owners.RetirementAuthority.Directory, j, service.Inventory, launch); err == nil {
147 t.Fatal("foreign session evidence")
148 }
149}
150