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 instancectl
4
5import (
6 "context"
7 "encoding/json"
8 "net"
9 "os"
10 "path/filepath"
11 "strings"
12 "testing"
13)
14
15func TestRev3ReservedUnitChecksAtTrampolineBoundary(t *testing.T) {
16 for _, name := range []string{"valid", "expired during setup", "wrong peer", "wrong reservation", "replacement invocation", "main PID handed over"} {
17 t.Run(name, func(t *testing.T) {
18 u, ctl, in, _ := claimUnitFixture(t)
19 dir, err := os.MkdirTemp("", "rg")
20 if err != nil {
21 t.Fatal(err)
22 }
23 defer os.RemoveAll(dir)
24 u.ExeRoot = filepath.Join(dir, "exe")
25 u.UnitRoot = filepath.Join(dir, "unit")
26 u.DataRoot = filepath.Join(dir, "data")
27 p := ClaimExecPermit{Reservation: "a:main", Inputs: "hash", BootID: "boot", SafeUntil: 200, Containment: 1}
28 setup := false
29 checks := 0
30 received := make(chan error, 1)
31 original := u.Systemctl
32 u.Systemctl = func(ctx context.Context, args ...string) (string, error) {
33 out, err := original(ctx, args...)
34 if name == "main PID handed over" && args[0] == "show" && strings.Contains(strings.Join(args, ","), "MainPID") {
35 ctl.mu.Lock()
36 ctl.pid = os.Getpid()
37 ctl.mu.Unlock()
38 }
39 if args[0] != "start" || err != nil {
40 return out, err
41 }
42 setup = true
43 ctl.mu.Lock()
44 ctl.pid = os.Getpid()
45 if name == "wrong peer" || name == "main PID handed over" {
46 ctl.pid++
47 }
48 ctl.mu.Unlock()
49 source, dropin, _ := u.launchPaths(in.Host)
50 body, e := os.ReadFile(filepath.Join(dropin, "60-claim-launch.conf"))
51 if e != nil || !strings.Contains(string(body), "BindReadOnlyPaths=/proc/sys/kernel/random/boot_id:"+ClaimExecBootID) || !strings.Contains(string(body), "instance-exec -claim-reservation="+ClaimExecSnapshot+" run %I\n") {
52 t.Errorf("missing trusted trampoline binds/argument: %s %v", body, e)
53 }
54 go func() {
55 c, e := net.Dial("unix", filepath.Join(source, "exec.sock"))
56 if e != nil {
57 received <- e
58 return
59 }
60 defer c.Close()
61 q := p
62 if name == "wrong reservation" {
63 q.Reservation = "other"
64 }
65 if e = json.NewEncoder(c).Encode(q); e == nil {
66 var got ClaimExecPermit
67 e = json.NewDecoder(c).Decode(&got)
68 }
69 received <- e
70 }()
71 return out, nil
72 }
73 l := Launch{Schema: LaunchSchema, Host: in.Host, Argv: []string{LiveDir + "/" + in.Host}}
74 started, err := u.StartReserved(t.Context(), in, l, p, func() error {
75 checks++
76 if setup && name == "expired during setup" {
77 return ErrClaimUnit
78 }
79 if setup && name == "replacement invocation" {
80 ctl.mu.Lock()
81 ctl.invocation = "replacement"
82 ctl.mu.Unlock()
83 }
84 return nil
85 })
86 clientErr := <-received
87 if name == "valid" || name == "main PID handed over" {
88 if err != nil || clientErr != nil || checks != 2 || started.MainPID != os.Getpid() {
89 t.Fatalf("start=%v gate=%v checks=%d", err, clientErr, checks)
90 }
91 source, _, _ := u.launchPaths(in.Host)
92 if _, err := os.Lstat(filepath.Join(source, "exec.sock")); err != nil {
93 t.Fatalf("ExecStopPost bind source removed early: %v", err)
94 }
95 _ = u.Stop(t.Context(), in.Host)
96 if _, err := os.Lstat(filepath.Join(source, "exec.sock")); !os.IsNotExist(err) {
97 t.Fatalf("stopped gate source retained: %v", err)
98 }
99 } else if err == nil || clientErr == nil {
100 t.Fatalf("unsafe start=%v gate=%v", err, clientErr)
101 }
102 if !strings.Contains(ctl.joined(), "start ") {
103 t.Fatal("did not reach asynchronous setup")
104 }
105 })
106 }
107}
108