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 unix
2
3package hostbox
4
5import (
6 "context"
7 "errors"
8 "os"
9 "path/filepath"
10 "testing"
11
12 "github.com/carlosframework/platform/internal/hostclaim"
13 "github.com/carlosframework/platform/internal/registry"
14)
15
16func TestEmptyCensusClassifiesSharedEntriesExactly(t *testing.T) {
17 ctx := context.Background()
18 base := t.TempDir()
19 db, err := OpenStopInventoryDB(filepath.Join(base, "inventory.db"))
20 if err != nil {
21 t.Fatal(err)
22 }
23 defer db.Close()
24 reg, err := registry.Open(filepath.Join(base, "registry.db"))
25 if err != nil {
26 t.Fatal(err)
27 }
28 defer reg.Close()
29 launches, err := OpenLaunchJournal(filepath.Join(base, "launch.db"))
30 if err != nil {
31 t.Fatal(err)
32 }
33 defer launches.Close()
34 roots := map[string]string{}
35 for _, name := range []string{"data", "opt", "units"} {
36 roots[name] = filepath.Join(base, name)
37 if err = os.Mkdir(roots[name], 0o700); err != nil {
38 t.Fatal(err)
39 }
40 }
41 at := func(root, rel string) string { return filepath.Join(roots[root], rel) }
42 write := func(path string) {
43 t.Helper()
44 if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
45 t.Fatal(err)
46 }
47 if err := os.WriteFile(path, []byte("x"), 0o644); err != nil {
48 t.Fatal(err)
49 }
50 }
51 link := func(target, path string) {
52 t.Helper()
53 if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
54 t.Fatal(err)
55 }
56 if err := os.Symlink(target, path); err != nil {
57 t.Fatal(err)
58 }
59 }
60 write(at("data", "opaque/anything"))
61 write(at("opt", "bin"))
62 write(at("opt", "store/v1/app"))
63 write(at("units", "a.service"))
64 link(at("units", "a.service"), at("units", "multi-user.target.wants/a.service"))
65 shared := map[string][]string{
66 "data": {"opaque"},
67 "opt": {CensusFile("bin"), CensusTree("store")},
68 "units": {CensusFile("a.service"), CensusLink("multi-user.target.wants/a.service", at("units", "a.service"))},
69 }
70 c := EmptyInstallationCensus{Inventory: db, Registry: reg, Launches: launches, Box: "box", Enrollment: "enrollment", DirectoryRevision: "revision", Roots: roots, SharedPaths: shared}
71 obs := hostclaim.Observed{Host: "shop.example", Claim: &hostclaim.Claim{Holder: &hostclaim.Holder{Incarnation: "inc", Stamp: 1}}}
72 selected := RecordSelection{Host: obs.Host, Incarnation: "inc"}
73 if err = c.CheckLocal(ctx, obs, selected); err != nil {
74 t.Fatalf("classified box: %v", err)
75 }
76 refuse := func(name string, mutate func() func()) {
77 t.Helper()
78 restore := mutate()
79 if err := c.CheckLocal(ctx, obs, selected); !errors.Is(err, ErrTypedInventory) {
80 t.Fatalf("%s: %v", name, err)
81 }
82 restore()
83 if err := c.CheckLocal(ctx, obs, selected); err != nil {
84 t.Fatalf("%s: not restored: %v", name, err)
85 }
86 }
87 remove := func(path string) func() {
88 return func() {
89 if err := os.RemoveAll(path); err != nil {
90 t.Fatal(err)
91 }
92 }
93 }
94 created := func(path string, put func(string)) func() func() {
95 return func() func() { put(path); return remove(path) }
96 }
97 swapped := func(path, target string) func() func() {
98 return func() func() {
99 old, err := os.Readlink(path)
100 if err != nil {
101 t.Fatal(err)
102 }
103 remove(path)()
104 link(target, path)
105 return func() { remove(path)(); link(old, path) }
106 }
107 }
108 refuse("symlink in a shared tree", created(at("opt", "store/v1/sh"), func(p string) { link("/bin/sh", p) }))
109 refuse("host name in a shared tree", created(at("opt", "store/v1/shop.example"), write))
110 refuse("unclassified file", created(at("opt", "other"), write))
111 refuse("substituted link target", swapped(at("units", "multi-user.target.wants/a.service"), at("units", "b.service")))
112 refuse("relative link target", swapped(at("units", "multi-user.target.wants/a.service"), "../a.service"))
113 refuse("foreign link into a managed root", created(at("units", "multi-user.target.wants/b.service"), func(p string) { link(at("opt", "bin"), p) }))
114 refuse("foreign link below a unit-root directory", created(at("units", "multi-user.target.wants/c.service"), func(p string) { link(at("units", "multi-user.target.wants/ssh.service"), p) }))
115 refuse("foreign link naming the platform", created(at("units", "d.service"), func(p string) { link("/srv/carlos/d.service", p) }))
116 refuse("foreign file naming the host", created(at("units", "e.service"), func(p string) {
117 if err := os.WriteFile(p, []byte("ExecStart=/srv/shop.example\n"), 0o644); err != nil {
118 t.Fatal(err)
119 }
120 }))
121 refuse("host-named foreign unit", created(at("units", "x@shop.example.service"), write))
122 refuse("file where a link is classified", func() func() {
123 path := at("units", "multi-user.target.wants/a.service")
124 remove(path)()
125 write(path)
126 return func() { remove(path)(); link(at("units", "a.service"), path) }
127 })
128 if err = os.Remove(at("opt", "bin")); err != nil {
129 t.Fatal(err)
130 }
131 link(at("opt", "store/v1/app"), at("opt", "bin"))
132 if err = c.CheckLocal(ctx, obs, selected); !errors.Is(err, ErrTypedInventory) {
133 t.Fatalf("symlink where a file is classified: %v", err)
134 }
135 remove(at("opt", "bin"))()
136 for name, bad := range map[string][]string{"relative link target": {CensusLink("x", "y")}, "escaping entry": {CensusFile("../x")}, "host entry": {CensusFile("shop.example")}, "conflicting entries": {CensusFile("x"), CensusTree("x")}} {
137 c.SharedPaths = map[string][]string{"data": shared["data"], "opt": append(append([]string{}, shared["opt"]...), bad...), "units": shared["units"]}
138 if err = c.CheckLocal(ctx, obs, selected); !errors.Is(err, ErrTypedInventory) {
139 t.Fatalf("%s accepted: %v", name, err)
140 }
141 }
142}
143