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 && rootrunner
2
3package host
4
5import (
6 "bytes"
7 "os"
8 "os/exec"
9 "path/filepath"
10 "syscall"
11 "testing"
12
13 "github.com/carlosframework/platform/internal/caps"
14 "github.com/carlosframework/platform/internal/release"
15 "github.com/carlosframework/platform/internal/rootparticipation"
16 "github.com/carlosframework/platform/internal/rootstate"
17)
18
19func TestPlan14RootCapabilitiesBothPaths(t *testing.T) {
20 if action := os.Getenv("PLAN14_CAPS_HOSTILE"); action != "" {
21 path := filepath.Join(rootparticipation.Namespace, "census.json")
22 var err error
23 if action == "renamed" {
24 err = os.Rename(path, path+"-old")
25 } else {
26 err = os.Remove(path)
27 }
28 if !os.IsPermission(err) {
29 t.Fatal("service UID mutated census", err)
30 }
31 return
32 }
33 if os.Geteuid() != 0 {
34 t.Fatal("root required")
35 }
36 if _, err := os.Lstat("/var/lib/carlos-claims"); !os.IsNotExist(err) {
37 t.Fatal("existing authority", err)
38 }
39 opt := t.TempDir()
40 o, effects := passOps(t)
41 rt := capsUnitRoute("keymail.dev", "keymail")
42 rt.Caps, rt.Channel = "port:25", "canary/x"
43 reg := openReg(t, rt)
44 set := &caps.Set{V: 1, Daemon: true, Ports: []caps.Port{{Port: 25}}}
45 store := release.NewDirStore(t.TempDir())
46 seed, public, _ := release.GenerateKey()
47 priv, _ := release.ParseSigningKey(seed, "test")
48 pub, _ := release.ParsePublicKey(public, "test")
49 for _, v := range []string{"aaaaaaa", "bbbbbbb"} {
50 m := release.Manifest{Schema: 1, App: rt.App, Version: v, Kind: "binary", Capabilities: set, Artifacts: map[string]release.Artifact{runtimePlatform(): {}}}
51 if err := release.Ship(t.Context(), store, release.OpsAccount, m, map[string][]byte{runtimePlatform(): []byte(v)}); err != nil {
52 t.Fatal(err)
53 }
54 }
55 promote := func(v string) {
56 t.Helper()
57 if err := release.Promote(t.Context(), store, priv, release.OpsAccount, rt.App, rt.Channel, v); err != nil {
58 t.Fatal(err)
59 }
60 }
61 adopt := func() {
62 t.Helper()
63 if err := release.Pass(t.Context(), reg, store, pub, opt, nil, release.WithCapabilities(o)); err != nil {
64 t.Fatal(err)
65 }
66 }
67 promote("aaaaaaa")
68 adopt()
69 if v, _ := release.LiveVersion(opt, rt.Host); v != "aaaaaaa" {
70 t.Fatal("no-census adoption refused", v)
71 }
72 if err := capabilityPass(reg, opt, o); err != nil {
73 t.Fatal(err)
74 }
75 svc, sock := readDropIns(t, o, rt.Host)
76 if sock == "" {
77 t.Fatal("legacy fixture made no drop-in")
78 }
79 if err := os.Mkdir("/var/lib/carlos-claims", 0700); err != nil {
80 t.Fatal(err)
81 }
82 defer os.RemoveAll("/var/lib/carlos-claims")
83 state, err := rootstate.Open(rootparticipation.Namespace, true, false)
84 if err != nil {
85 t.Fatal(err)
86 }
87 defer state.Close()
88 if err = state.Write("census.json", []byte(`{"schema":1}`)); err != nil {
89 t.Fatal(err)
90 }
91 callbacks := 0
92 o.Authorize = func() error { callbacks++; return nil }
93 promote("bbbbbbb")
94 for _, grant := range []string{"host-role", "doc-engine", "", "port:25,port:587"} {
95 t.Run(grant, func(t *testing.T) {
96 current, err := reg.Get(rt.Host)
97 if err != nil || current == nil {
98 t.Fatal(err)
99 }
100 if err := reg.SetCaps(rt.Host, current.Caps, grant); err != nil {
101 t.Fatal(err)
102 }
103 effects.calls, effects.users = nil, nil
104 if err := capabilityPass(reg, opt, o); err != nil {
105 t.Fatal(err)
106 }
107 adopt()
108 a, b := readDropIns(t, o, rt.Host)
109 if a != svc || b != sock || len(effects.calls) != 0 || len(effects.users) != 0 || callbacks != 0 {
110 t.Fatal("census permitted unit mutation", effects)
111 }
112 if v, _ := release.LiveVersion(opt, rt.Host); v != "aaaaaaa" {
113 t.Fatal("refused adoption repointed", v)
114 }
115 })
116 }
117 guarded := o
118 if err := caps.Restore(guarded, caps.Snapshot{Host: rt.Host}); err == nil {
119 t.Fatal("restore bypass")
120 }
121 if err := caps.Restart(guarded, caps.Plan{Host: rt.Host}); err == nil {
122 t.Fatal("restart bypass")
123 }
124 for _, hostile := range []string{"corrupt", "renamed", "erased"} {
125 t.Run(hostile, func(t *testing.T) {
126 path := filepath.Join(rootparticipation.Namespace, "census.json")
127 if hostile == "corrupt" {
128 if err := os.WriteFile(path, []byte("corrupt"), 0600); err != nil {
129 t.Fatal(err)
130 }
131 } else {
132 binary, err := os.Open(os.Args[0])
133 if err != nil {
134 t.Fatal(err)
135 }
136 defer binary.Close()
137 cmd := exec.Command("/proc/self/fd/3", "-test.run=^TestPlan14RootCapabilitiesBothPaths$")
138 cmd.ExtraFiles = []*os.File{binary}
139 cmd.Env = append(os.Environ(), "PLAN14_CAPS_HOSTILE="+hostile)
140 cmd.SysProcAttr = &syscall.SysProcAttr{Credential: &syscall.Credential{Uid: 65534, Gid: 65534}}
141 if out, err := cmd.CombinedOutput(); err != nil {
142 t.Fatal(err, string(out))
143 }
144 }
145 if _, err := caps.Converge(guarded, caps.Plan{Host: rt.Host}); err == nil {
146 t.Fatal("retained census permitted converge")
147 }
148 })
149 }
150 a, b := readDropIns(t, o, rt.Host)
151 if !bytes.Equal([]byte(a+b), []byte(svc+sock)) {
152 t.Fatal("fixed unit changed")
153 }
154}
155