carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package instancekey
2
3import (
4 "strings"
5 "testing"
6)
7
8// Finding 4: an empty own value never shadows a configured key; a
9// non-empty own value always wins.
10func TestEffectiveNeverHandsOutAnEmptyKeyWhileOneExists(t *testing.T) {
11 for _, tc := range []struct {
12 name string
13 config, own string
14 want string
15 layer Layer
16 }{
17 {"own wins", Var + "=cfg\n", Var + "=own\n", "own", LayerOwn},
18 {"empty own, configured", Var + "=cfg\n", Var + "=\n", "cfg", LayerConfig},
19 {"no own, configured", Var + "=cfg\n", "A=1\n", "cfg", LayerConfig},
20 {"own only", "", Var + "=own\n", "own", LayerOwn},
21 {"both empty", Var + "=\n", Var + "=\n", "", LayerNone},
22 {"exported is not the key", "", "export " + Var + "=own\n", "", LayerNone},
23 } {
24 t.Run(tc.name, func(t *testing.T) {
25 got, layer := Effective(ParseEnv([]byte(tc.config)), ParseEnv([]byte(tc.own)))
26 if got != tc.want || layer != tc.layer {
27 t.Fatalf("Effective = %q, %v; want %q, %v", got, layer, tc.want, tc.layer)
28 }
29 })
30 }
31}
32
33// Ruling 20 (R-B): a record binds one writer. Another session, another
34// generation, another installation or another host never matches, so a
35// later release that picks its own key, a rollback and a reinstall never
36// inherit an earlier writer's adoption.
37func TestAdoptionRecordBindsOneWriter(t *testing.T) {
38 key := strings.Repeat("A", 43) + "="
39 w := Binding{Host: "shop.example.com", Incarnation: "inc-1", Session: 3, Generation: "g3"}
40 rec := AdoptionRecord(w, SourcePlatform, Digest(key))
41 if strings.Contains(string(rec), key) {
42 t.Fatal("the record holds the key itself")
43 }
44 a, err := ParseAdoption(rec)
45 if err != nil || !a.Binds(w) || a.Source != SourcePlatform || a.SHA256 != Digest(key) {
46 t.Fatalf("ParseAdoption = %+v, %v", a, err)
47 }
48 for name, other := range map[string]Binding{
49 "an earlier session (an earlier release)": {Host: w.Host, Incarnation: w.Incarnation, Session: 2, Generation: "g2"},
50 "a later session (a rollback)": {Host: w.Host, Incarnation: w.Incarnation, Session: 4, Generation: "g4"},
51 "the same session, another generation": {Host: w.Host, Incarnation: w.Incarnation, Session: 3, Generation: "g3b"},
52 "another installation (a reinstall)": {Host: w.Host, Incarnation: "inc-2", Session: 3, Generation: "g3"},
53 "another host": {Host: "other.example.com", Incarnation: w.Incarnation, Session: 3, Generation: "g3"},
54 "no writer": {},
55 } {
56 if a.Binds(other) {
57 t.Errorf("%s: the record matched", name)
58 }
59 }
60 for name, raw := range map[string]string{
61 "version 1": `{"v":1,"var":"CARLOS_INSTANCE_KEY","sha256":"` + Digest(key) + `"}`,
62 "no binding": `{"v":2,"var":"CARLOS_INSTANCE_KEY","source":"platform","sha256":"` + Digest(key) + `"}`,
63 "unknown source": `{"v":2,"var":"CARLOS_INSTANCE_KEY","host":"h","incarnation":"i","session":1,"generation":"g","source":"own","sha256":"` + Digest(key) + `"}`,
64 "an unknown field": `{"v":2,"var":"CARLOS_INSTANCE_KEY","host":"h","incarnation":"i","session":1,"generation":"g","source":"config","sha256":"` + Digest(key) + `","key":"x"}`,
65 "trailing data": string(rec) + `{}`,
66 "garbage": "not json",
67 // The canonical bytes are the only record (review minor 1):
68 // encoding/json alone accepts each of these.
69 "a trailing }": string(rec) + `}`,
70 "a trailing ]": string(rec) + `]`,
71 "an upper-case key": strings.Replace(string(rec), `"sha256"`, `"SHA256"`, 1),
72 "a key given twice": strings.Replace(string(rec), `"source":"platform"`, `"source":"config","source":"platform"`, 1),
73 "reordered fields": strings.Replace(string(rec), `{"v":2,"var":"CARLOS_INSTANCE_KEY",`, `{"var":"CARLOS_INSTANCE_KEY","v":2,`, 1),
74 "an upper-case digest": strings.Replace(string(rec), Digest(key), strings.ToUpper(Digest(key)), 1),
75 "a short digest": strings.Replace(string(rec), Digest(key), Digest(key)[:63], 1),
76 "another variable": strings.Replace(string(rec), `"var":"CARLOS_INSTANCE_KEY"`, `"var":"OTHER"`, 1),
77 } {
78 if raw == string(rec) {
79 t.Fatalf("%s: the case did not change the record", name)
80 }
81 if _, err := ParseAdoption([]byte(raw)); err == nil {
82 t.Errorf("%s: parsed", name)
83 }
84 }
85}
86
87// ParseEnv is exactly the activator's old parseEnvBytes, so what a reader
88// parses is what a child received: quotes kept, whole-line comments only,
89// the last duplicate winning, CRLF and surrounding whitespace trimmed.
90func TestParseEnvMatchesWhatAChildReceives(t *testing.T) {
91 got := ParseEnv([]byte("A=\"quoted\"\nB='single'\n# C=1\n # D=1\nE=1 # kept\nF=1\nF=2\n G = spaced \nH=a=b\nI=1\r\nnoequals\n\n"))
92 want := map[string]string{"A": `"quoted"`, "B": "'single'", "E": "1 # kept", "F": "2", "G": "spaced", "H": "a=b", "I": "1"}
93 if len(got) != len(want) {
94 t.Fatalf("ParseEnv = %q, want %q", got, want)
95 }
96 for k, v := range want {
97 if got[k] != v {
98 t.Fatalf("ParseEnv = %q, want %q", got, want)
99 }
100 }
101}
102
103// O3': the install refuses env files that would deliver any key but the
104// pinned one, including a configuration changed since the pin.
105func TestVerifyDeliveredRefusesAnyOtherKey(t *testing.T) {
106 a, b := strings.Repeat("A", 43)+"=", strings.Repeat("B", 43)+"="
107 for _, tc := range []struct {
108 name, config, own string
109 ok bool
110 }{
111 {"the configured key, unchanged", Var + "=" + a + "\n", "T=1\n", true},
112 {"the configuration changed since the pin", Var + "=" + b + "\n", "T=1\n", false},
113 {"the configured key removed", "", "T=1\n", false},
114 {"an empty override over the configured key", Var + "=" + a + "\n", Var + "=\n", true},
115 {"the platform key, restored", "", Var + "=" + a + "\n", true},
116 {"a platform key over the pinned configured one", Var + "=" + a + "\n", Var + "=" + b + "\n", false},
117 } {
118 if err := VerifyDelivered([]byte(tc.config), []byte(tc.own), Digest(a)); (err == nil) != tc.ok {
119 t.Errorf("%s: err = %v", tc.name, err)
120 }
121 }
122}
123
124// Ruling 26: the pre-roll check's verified home keys, as the box reads
125// them. A list that may be wrong verifies nothing, and its errors never
126// echo an entry, which may hold a digest (Astra round 5 finding 3).
127func TestParseHomeKeys(t *testing.T) {
128 a, b := Digest("home-key-a"), Digest("home-key-b")
129 got, err := ParseHomeKeys(" shop-au.example.com=" + a + ", shop-uk.example.com=" + b + ",")
130 if err != nil || len(got) != 2 || got["shop-au.example.com"] != a || got["shop-uk.example.com"] != b {
131 t.Fatalf("ParseHomeKeys = %v, %v", got, err)
132 }
133 if got, err := ParseHomeKeys(""); err != nil || len(got) != 0 {
134 t.Fatalf("empty = %v, %v", got, err)
135 }
136 for _, tc := range []struct{ value, want string }{
137 {a, "entry 1: no \"replica-host=\""},
138 {"shop-au.example.com=" + a + "," + b, "entry 2: no \"replica-host=\""},
139 {"shop-au.example.com=" + a[:40], "entry 1: the digest is not"},
140 {"=" + a, "entry 1: the host is empty"},
141 {a[:20] + "=" + a, "entry 1: the host is empty or not a host name"},
142 {"shop-au.example.com=" + a + ",shop-au.example.com=" + b, "entry 2: its host is listed"},
143 } {
144 _, err := ParseHomeKeys(tc.value)
145 if err == nil || !strings.Contains(err.Error(), tc.want) {
146 t.Errorf("%q: err = %v, want %q", tc.value, err, tc.want)
147 continue
148 }
149 if strings.Contains(err.Error(), a[:16]) || strings.Contains(err.Error(), b[:16]) || strings.Contains(err.Error(), "shop-") {
150 t.Errorf("the error echoes its input: %v", err)
151 }
152 }
153}
154