carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "bytes"
5 "context"
6 "errors"
7 "net/http"
8 "os"
9 "os/exec"
10 "reflect"
11 "strings"
12 "testing"
13)
14
15func TestSystemVerbKnowsBoxAndGroup(t *testing.T) {
16 for _, verb := range []string{"box", "group"} {
17 got, rest, _ := systemVerb([]string{verb, "role", "x", "legacy"})
18 if got != verb || len(rest) != 3 || rest[0] != "role" {
19 t.Fatalf("systemVerb(%s) = %q %q", verb, got, rest)
20 }
21 }
22}
23
24// carlos system box publish-record reaches the box verb, not the console
25// role call: run in a child on a fleet box, it prints the fleet refusal
26// (or, as root, the root refusal) and exits 1 before any store, console
27// or IMDS is touched.
28func TestSystemBoxPublishRecordDispatch(t *testing.T) {
29 if os.Getenv("CARLOS_TEST_PUBLISH_RECORD_CHILD") == "1" {
30 runSystem([]string{"box", "publish-record"})
31 os.Exit(0)
32 }
33 cmd := exec.Command(os.Args[0], "-test.run=^TestSystemBoxPublishRecordDispatch$")
34 scratch := t.TempDir()
35 cmd.Dir = scratch
36 cmd.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + scratch, "CARLOS_TEST_PUBLISH_RECORD_CHILD=1",
37 "CARLOS_FLEET=acme", "CARLOS_FLEET_BOX=kass-1"}
38 var stdout, stderr bytes.Buffer
39 cmd.Stdout, cmd.Stderr = &stdout, &stderr
40 err := cmd.Run()
41 var exit *exec.ExitError
42 if !errors.As(err, &exit) || exit.ExitCode() != 1 {
43 t.Fatalf("exit: %v; stdout %q stderr %q", err, stdout.String(), stderr.String())
44 }
45 want := "this is a fleet box. fleet boxes publish no identity record, so nothing was written"
46 if os.Geteuid() == 0 { // root is refused first (census ruling R1)
47 want = "carlos system box publish-record runs as the agent user, not root. run it with systemd-run -p User=carlos."
48 }
49 if got := strings.TrimSpace(stderr.String()); got != want {
50 t.Fatalf("stderr = %q", got)
51 }
52}
53
54// fakeRolePost answers one role call with status and body, recording what
55// was asked.
56type fakeRolePost struct {
57 status int
58 body string
59 path string
60 in any
61}
62
63func (f *fakeRolePost) post(_ context.Context, path string, in any) (int, []byte, error) {
64 f.path, f.in = path, in
65 return f.status, []byte(f.body), nil
66}
67
68func TestSetBoxRole(t *testing.T) {
69 f := &fakeRolePost{status: http.StatusOK, body: `{"box":"i-0abc","role":"legacy"}`}
70 line, err := setBoxRole(context.Background(), f.post, "old box", "legacy")
71 if err != nil || line != "i-0abc now has the legacy role" {
72 t.Fatalf("line %q, %v", line, err)
73 }
74 if f.path != "/api/cli/system/boxes/old%20box/role" || !reflect.DeepEqual(f.in, map[string]string{"role": "legacy"}) {
75 t.Fatalf("asked %s %v", f.path, f.in)
76 }
77 f = &fakeRolePost{status: http.StatusBadRequest, body: `{"error":"role must be default, legacy or platform"}`}
78 if _, err := setBoxRole(context.Background(), f.post, "x", "boss"); err == nil || err.Error() != "role must be default, legacy or platform" {
79 t.Fatalf("refusal: %v", err)
80 }
81 failing := func(context.Context, string, any) (int, []byte, error) { return 0, nil, errors.New("offline") }
82 if _, err := setBoxRole(context.Background(), failing, "x", "legacy"); err == nil {
83 t.Fatal("a failed call printed a line")
84 }
85}
86
87func TestSetGroupRole(t *testing.T) {
88 f := &fakeRolePost{status: http.StatusOK, body: `{"region":"ie","group":"routers","role":"legacy","boxes":["i-1","i-2"]}`}
89 lines, err := setGroupRole(context.Background(), f.post, "ie", "legacy")
90 if err != nil {
91 t.Fatal(err)
92 }
93 want := []string{"the group in ie now has the legacy role", "i-1 now has the legacy role", "i-2 now has the legacy role"}
94 if !reflect.DeepEqual(lines, want) || f.path != "/api/cli/system/groups/ie/role" {
95 t.Fatalf("lines %q path %s", lines, f.path)
96 }
97 f = &fakeRolePost{status: http.StatusOK, body: `{"region":"ie","group":"routers","role":"default","boxes":[]}`}
98 if lines, _ := setGroupRole(context.Background(), f.post, "ie", "default"); len(lines) != 1 {
99 t.Fatalf("an empty group: %q", lines)
100 }
101}
102