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 "context"
8 "crypto/sha256"
9 "database/sql"
10 "encoding/hex"
11 "flag"
12 "io"
13 "net"
14 "net/http"
15 "os"
16 "os/exec"
17 "path/filepath"
18 "strings"
19 "testing"
20 "time"
21
22 "github.com/carlosframework/platform/internal/activator"
23 "github.com/carlosframework/platform/internal/cgroup"
24 "github.com/carlosframework/platform/internal/hostclaim"
25 "github.com/carlosframework/platform/internal/provision"
26 "github.com/carlosframework/platform/internal/registry"
27)
28
29var seedTenantSocket = flag.String("socket", "", "")
30var seedTenantDB = flag.String("db", "", "")
31
32func init() {
33 if os.Getenv("FILES_SEED_TENANT") == "1" {
34 os.Args = append(os.Args, "-test.run=^TestRootFilesSeedTenantPayload$", "-test.timeout=30s")
35 }
36}
37
38// This process is launched from the ordinary selected Build closure after C8.
39// The surrounding fixture still supplies role authority and stop evidence;
40// this witness does not stand in for the installed isolated role-launch test.
41func TestRootFilesSeedTenantPayload(t *testing.T) {
42 if os.Getenv("FILES_SEED_TENANT") != "1" {
43 t.Fatal("invoke through real-origin tenant witness")
44 }
45 for _, path := range strings.Split(os.Getenv("FILES_SEED_DENIED"), ":") {
46 if path != "" {
47 if body, err := os.ReadFile(path); err == nil {
48 _ = os.WriteFile(os.Getenv("FILES_SEED_PAYLOAD")+".isolation-violation", []byte(path), 0600)
49 t.Fatalf("tenant read foreign path %s: %q", path, body)
50 }
51 if f, err := os.OpenFile(path, os.O_WRONLY, 0); err == nil {
52 f.Close()
53 t.Fatalf("tenant opened foreign path for write: %s", path)
54 }
55 }
56 }
57 db, err := sql.Open("sqlite", *seedTenantDB)
58 if err != nil {
59 t.Fatal(err)
60 }
61 defer db.Close()
62 var integrity string
63 if err := db.QueryRow("PRAGMA integrity_check").Scan(&integrity); err != nil || integrity != "ok" {
64 t.Fatal(integrity, err)
65 }
66 body, err := os.ReadFile(os.Getenv("FILES_SEED_PAYLOAD"))
67 expected := os.Getenv("FILES_SEED_EXPECTED")
68 if expected == "" {
69 expected = "real seeded bytes"
70 }
71 if err != nil || string(body) != expected {
72 t.Fatal(string(body), err)
73 }
74 listener, err := net.Listen("unix", *seedTenantSocket)
75 if err != nil {
76 t.Fatal(err)
77 }
78 defer listener.Close()
79 server := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write(body) })}
80 defer server.Close()
81 if err := server.Serve(listener); err != nil {
82 t.Fatal(err)
83 }
84}
85
86func rootFilesSeedLiveWitness(t *testing.T, binary string) filesSeedLiveWitness {
87 body, err := os.ReadFile(binary)
88 if err != nil {
89 t.Fatal(err)
90 }
91 digest := sha256.Sum256(body)
92 return filesSeedLiveWitness{configure: func(w *ClaimWakeAssembly) {
93 owners := w.Inputs.(*claimServingOwners)
94 selectLaunch := owners.Sources.Launch
95 owners.Sources.Launch = func(ctx context.Context, rt registry.Route) (ClaimServingLaunch, error) {
96 launch, err := selectLaunch(ctx, rt)
97 if err != nil {
98 return launch, err
99 }
100 launch.Executable = binary
101 launch.ExecutableSHA256 = hex.EncodeToString(digest[:])
102 launch.Env = append(launch.Env, "FILES_SEED_TENANT=1", "FILES_SEED_PAYLOAD="+filepath.Join(filepath.Dir(rt.DBPath), rt.Host, "payload"))
103 return launch, nil
104 }
105 }, serve: func(t *testing.T, p *servingPreparation, o hostclaim.Observed, start activator.ClaimStart) {
106 socket := provision.NestedSocket(o.Host)
107 if err := os.MkdirAll(filepath.Dir(socket), 0700); err != nil {
108 t.Fatal(err)
109 }
110 cmd := start.Build()
111 cmd.Stdin = os.Stdin
112 var output bytes.Buffer
113 cmd.Stdout = &output
114 cmd.Stderr = &output
115 if err := cmd.Start(); err != nil {
116 t.Fatal(err)
117 }
118 // No readiness or success is fabricated: the selected process owns the socket.
119 defer func() { cmd.Process.Kill(); cmd.Wait(); os.Remove(socket) }()
120 ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second)
121 defer cancel()
122 if err := start.Ready(ctx, cmd); err != nil {
123 cmd.Process.Kill()
124 cmd.Wait()
125 t.Fatalf("tenant readiness: %v %s", err, output.String())
126 }
127 transport := &http.Transport{DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
128 return (&net.Dialer{}).DialContext(ctx, "unix", socket)
129 }}
130 defer transport.CloseIdleConnections()
131 response, err := (&http.Client{Transport: transport, Timeout: time.Second}).Get("http://tenant/")
132 if err != nil {
133 t.Fatal(err)
134 }
135 payload, err := io.ReadAll(response.Body)
136 response.Body.Close()
137 if err != nil || response.StatusCode != 200 || string(payload) != "real seeded bytes" {
138 t.Fatal("tenant served wrong restored payload", err, string(payload))
139 }
140 wrong, _ := os.FindProcess(os.Getpid())
141 refuse, stop := context.WithTimeout(t.Context(), 40*time.Millisecond)
142 defer stop()
143 if err := start.Ready(refuse, &exec.Cmd{Process: wrong}); err == nil {
144 t.Fatal("readiness accepted controller instead of tenant")
145 }
146 }}
147}
148
149func TestFilesSeedLiveFixtureShape(t *testing.T) {
150 binary, err := os.Executable()
151 if err != nil {
152 t.Fatal(err)
153 }
154 witness := rootFilesSeedLiveWitness(t, binary)
155 f := plan9D5Fixture(t)
156 rt := registry.Route{Host: recoveryHost, DBPath: provision.NestedDBPath("/data", recoveryHost), Socket: provision.NestedSocket(recoveryHost)}
157 f.launch.Args = []string{"--socket", rt.Socket, "--db", rt.DBPath}
158 f.launch.Env = []string{"CARLOS_ADMIN_TOKEN=test"}
159 w := &ClaimWakeAssembly{Inputs: f.owners}
160 witness.configure(w)
161 launch, err := f.owners.Sources.Launch(t.Context(), rt)
162 if err != nil {
163 t.Fatal(err)
164 }
165 role := &ClaimRoleAssembly{Root: fakeLaunchRoot{}, ManagedRoots: map[string]string{"data": "/data"}}
166 in := ClaimLaunchInputs{Limit: cgroup.TierDefault, Roles: []string{"main"}, Identity: launch.Identity, Executable: launch.Executable, ExecutableSHA256: launch.ExecutableSHA256, Args: launch.Args, Env: launch.Env, DBPath: rt.DBPath}
167 if err := role.PreflightLaunch(rt.Host, in); err != nil {
168 t.Fatal(err, launch.Args, launch.Env)
169 }
170}
171