| 1 | package moves |
| 2 | |
| 3 | import ( |
| 4 | "encoding/base64" |
| 5 | "strings" |
| 6 | "testing" |
| 7 | ) |
| 8 | |
| 9 | func TestEnvReportRevealsNamesAndEqualityOnly(t *testing.T) { |
| 10 | key := []byte("0123456789abcdef0123456789abcdef") |
| 11 | src := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_REGION": "ie", "CARLOS_CONTROL_SOCKET": "/run/x", "INVOCATION_ID": "1", "SECRET": "s3"}) |
| 12 | if src.Vars["SECRET"] == "s3" || len(src.Vars["SECRET"]) != 64 { |
| 13 | t.Fatal("a value leaked or the mac is not hex sha256") |
| 14 | } |
| 15 | same := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_REGION": "uk", "CARLOS_CONTROL_SOCKET": "/run/y", "INVOCATION_ID": "2", "SECRET": "s3"}) |
| 16 | if diffs := CompareEnv(src, same, true, false); len(diffs) != 0 { |
| 17 | t.Fatalf("a matching target reported %v", diffs) |
| 18 | } |
| 19 | // Region must differ; layout vars are present iff flat provides them; |
| 20 | // box vars are never compared; everything else equal. |
| 21 | sameRegion := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_REGION": "ie", "CARLOS_CONTROL_SOCKET": "/run/y", "SECRET": "s3"}) |
| 22 | diffs := CompareEnv(src, sameRegion, true, false) |
| 23 | if len(diffs) != 1 || diffs[0].Name != "CARLOS_REGION" || diffs[0].Kind != "region-same" { |
| 24 | t.Fatalf("same region: %v", diffs) |
| 25 | } |
| 26 | noRegion := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_CONTROL_SOCKET": "/run/y", "SECRET": "s3"}) |
| 27 | if diffs := CompareEnv(src, noRegion, true, false); len(diffs) != 1 || diffs[0].Kind != "region-missing" { |
| 28 | t.Fatalf("missing region: %v", diffs) |
| 29 | } |
| 30 | // the layout variable absent from both: still required of a flat landing |
| 31 | srcNoLayout := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_REGION": "ie"}) |
| 32 | if diffs := CompareEnv(srcNoLayout, ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_REGION": "uk"}), true, false); len(diffs) != 1 || diffs[0].Name != "CARLOS_CONTROL_SOCKET" || diffs[0].Kind != "layout-missing" { |
| 33 | t.Fatalf("layout name absent from both: %v", diffs) |
| 34 | } |
| 35 | // CARLOS_PURGE is advisory (set iff the box has a cache): a presence |
| 36 | // difference is a note, never a failure; main omits the variable on a |
| 37 | // box without a cache (backend_exec.go agentOwnedVars), so neither |
| 38 | // example above carries it and they compare clean. |
| 39 | purge := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:a", "CARLOS_REGION": "uk", "CARLOS_CONTROL_SOCKET": "/run/y", "SECRET": "s3", "CARLOS_PURGE": "header"}) |
| 40 | if diffs := CompareEnv(src, purge, true, false); len(diffs) != 1 || diffs[0].Name != "CARLOS_PURGE" || diffs[0].Kind != "advisory-differs" || !diffs[0].Note() { |
| 41 | t.Fatalf("purge presence: %v", diffs) |
| 42 | } |
| 43 | drift := ReportEnv(key, map[string]string{"DATABASE_URL": "sqlite:b", "CARLOS_REGION": "uk", "EXTRA": "x"}) |
| 44 | kinds := map[string]string{} |
| 45 | for _, d := range CompareEnv(src, drift, false, false) { |
| 46 | kinds[d.Name] = d.Kind |
| 47 | } |
| 48 | if kinds["DATABASE_URL"] != "differs" || kinds["SECRET"] != "missing" || kinds["EXTRA"] != "extra" || kinds["CARLOS_CONTROL_SOCKET"] != "" { |
| 49 | t.Fatalf("drift: %v", kinds) |
| 50 | } |
| 51 | if ReportEnv([]byte("another-key-another-key-another!"), map[string]string{"SECRET": "s3"}).Vars["SECRET"] == src.Vars["SECRET"] { |
| 52 | t.Fatal("the mac does not depend on the key") |
| 53 | } |
| 54 | // The digest is the move-portable one (home part 2, Task 2b): src and |
| 55 | // same differ only in box-owned variables (region, control socket, a |
| 56 | // box variable), so they pin the same; drift differs in the instance's |
| 57 | // own variables, so it does not. |
| 58 | if src.Digest == "" || src.Digest != same.Digest || src.Digest == drift.Digest { |
| 59 | t.Fatalf("digest: src %s same %s drift %s", src.Digest, same.Digest, drift.Digest) |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | // TestBoxOwnedIsTheOneSharedSet: the box-owned set is the agent-owned |
| 64 | // variables and the box variables, T3 tolerates exactly it (every |
| 65 | // box-owned name has a class other than "equal", every other name is |
| 66 | // "equal"), and the layout, advisory and region classes are inside it. |
| 67 | func TestBoxOwnedIsTheOneSharedSet(t *testing.T) { |
| 68 | for _, set := range []map[string]bool{AgentOwnedVars, BoxVars, LayoutVars, AdvisoryVars, {RegionVar: true}} { |
| 69 | for name := range set { |
| 70 | if !BoxOwned(name) || Class(name) == "equal" { |
| 71 | t.Errorf("%s: box-owned %v, class %q", name, BoxOwned(name), Class(name)) |
| 72 | } |
| 73 | } |
| 74 | } |
| 75 | for _, name := range []string{"CARLOS_REGION", "CARLOS_CONTROL_SOCKET", "CARLOS_PURGE", "CARLOS_HOST"} { |
| 76 | if !AgentOwnedVars[name] { |
| 77 | t.Errorf("%s is not agent-owned", name) |
| 78 | } |
| 79 | } |
| 80 | if Class("CARLOS_HOST") != "box" { |
| 81 | t.Errorf("CARLOS_HOST is class %q, want box", Class("CARLOS_HOST")) |
| 82 | } |
| 83 | for _, name := range []string{"DATABASE_URL", "CARLOS_ADMIN_TOKEN", "CARLOS_INSTANCE_KEY", "APP_MODE", "PATH", "HOME"} { |
| 84 | if BoxOwned(name) || Class(name) != "equal" { |
| 85 | t.Errorf("%s: box-owned %v, class %q", name, BoxOwned(name), Class(name)) |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | // TestPortableDigestCoversTheInstanceOnly: the pin ignores every |
| 91 | // agent-owned variable, and every box variable the box supplied, present, |
| 92 | // absent or different, and still binds every instance variable: its value, |
| 93 | // its presence, its name. A box variable the instance's own layers |
| 94 | // supplied is the instance's (fix round 2): its value and its presence are |
| 95 | // pinned like an app variable's. |
| 96 | func TestPortableDigestCoversTheInstanceOnly(t *testing.T) { |
| 97 | key := []byte("0123456789abcdef0123456789abcdef") |
| 98 | base := map[string]string{"APP_MODE": "prod", "DATABASE_URL": "sqlite:a"} |
| 99 | pin := PortableDigest(key, base, nil) |
| 100 | if pin != ReportEnv(key, base).Digest || pin != ReportLaunch(key, base, map[string]bool{"APP_MODE": true}).Digest { |
| 101 | t.Fatal("PortableDigest is not ReportLaunch's digest") |
| 102 | } |
| 103 | with := func(edit func(map[string]string), instance map[string]bool) string { |
| 104 | env := map[string]string{} |
| 105 | for k, v := range base { |
| 106 | env[k] = v |
| 107 | } |
| 108 | edit(env) |
| 109 | return PortableDigest(key, env, instance) |
| 110 | } |
| 111 | for name := range AgentOwnedVars { |
| 112 | // agent-owned and the box's: left out |
| 113 | if got := with(func(e map[string]string) { e[name] = "box-a" }, nil); got != pin { |
| 114 | t.Errorf("%s from the box changed the pin", name) |
| 115 | } |
| 116 | // the exclusion rule (fix round 4): a box-owned name the instance |
| 117 | // supplied is pinned. The composer never reports an agent-owned |
| 118 | // name so (ExecBackend.LaunchLayers), as the agent decides it. |
| 119 | if got := with(func(e map[string]string) { e[name] = "box-a" }, map[string]bool{name: true}); got == pin { |
| 120 | t.Errorf("%s supplied by the instance left the pin unchanged", name) |
| 121 | } |
| 122 | } |
| 123 | for name := range BoxVars { |
| 124 | if got := with(func(e map[string]string) { e[name] = "box-b" }, nil); got != pin { |
| 125 | t.Errorf("%s inherited from the box changed the pin", name) |
| 126 | } |
| 127 | if got := with(func(e map[string]string) { e[name] = "box-b" }, map[string]bool{name: true}); got == pin { |
| 128 | t.Errorf("%s supplied by the instance left the pin unchanged", name) |
| 129 | } |
| 130 | } |
| 131 | a := with(func(e map[string]string) { e["HOSTNAME"] = "a" }, map[string]bool{"HOSTNAME": true}) |
| 132 | if b := with(func(e map[string]string) { e["HOSTNAME"] = "b" }, map[string]bool{"HOSTNAME": true}); a == b { |
| 133 | t.Error("an instance HOSTNAME's value is not pinned") |
| 134 | } |
| 135 | if inherited := with(func(e map[string]string) { e["HOSTNAME"] = "a" }, nil); inherited == a { |
| 136 | t.Error("the same HOSTNAME pins the same whether the box or the instance supplied it") |
| 137 | } |
| 138 | for name, edit := range map[string]func(map[string]string){ |
| 139 | "a value": func(e map[string]string) { e["APP_MODE"] = "staging" }, |
| 140 | "an extra": func(e map[string]string) { e["EXTRA"] = "1" }, |
| 141 | "a missing": func(e map[string]string) { delete(e, "DATABASE_URL") }, |
| 142 | "a rename": func(e map[string]string) { e["APP_MODE2"] = e["APP_MODE"]; delete(e, "APP_MODE") }, |
| 143 | } { |
| 144 | if with(edit, nil) == pin { |
| 145 | t.Errorf("%s instance variable left the pin unchanged", name) |
| 146 | } |
| 147 | } |
| 148 | // The local digest covers everything, box-owned variables included. |
| 149 | local := LocalDigest(key, base) |
| 150 | if local == LocalDigest(key, map[string]string{"APP_MODE": "prod", "DATABASE_URL": "sqlite:a", RegionVar: "uk"}) || |
| 151 | local == LocalDigest(key, map[string]string{"APP_MODE": "prod", "DATABASE_URL": "sqlite:a", "HOSTNAME": "box"}) { |
| 152 | t.Error("the local digest ignored a box-owned variable") |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // TestPinnedRule (fix round 4, platform-1e's exclusion rule): a name is |
| 157 | // left out only when it is box-owned and the instance did not supply it; |
| 158 | // everything else is pinned. |
| 159 | func TestPinnedRule(t *testing.T) { |
| 160 | for _, c := range []struct { |
| 161 | name string |
| 162 | instance bool |
| 163 | want bool |
| 164 | }{ |
| 165 | {RegionVar, false, false}, {RegionVar, true, true}, {"CARLOS_HOST", false, false}, {"CARLOS_HOST", true, true}, |
| 166 | {"HOSTNAME", false, false}, {"HOSTNAME", true, true}, {"PWD", true, true}, |
| 167 | {"APP_MODE", false, true}, {"APP_MODE", true, true}, |
| 168 | } { |
| 169 | if got := Pinned(c.name, c.instance); got != c.want { |
| 170 | t.Errorf("Pinned(%s, %v) = %v, want %v", c.name, c.instance, got, c.want) |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | // TestCompareEnvComparesAnInstanceBoxVariable (fix round 2): T3 compares a |
| 176 | // box variable either side's instance supplied as an app variable, and |
| 177 | // still ignores one both boxes supplied. |
| 178 | func TestCompareEnvComparesAnInstanceBoxVariable(t *testing.T) { |
| 179 | key := []byte("0123456789abcdef0123456789abcdef") |
| 180 | src := ReportLaunch(key, map[string]string{"A": "1", RegionVar: "ie", "HOSTNAME": "a"}, map[string]bool{"A": true, "HOSTNAME": true}) |
| 181 | if len(src.Instance) != 1 || src.Instance[0] != "HOSTNAME" { |
| 182 | t.Fatalf("Instance %v", src.Instance) |
| 183 | } |
| 184 | same := ReportLaunch(key, map[string]string{"A": "1", RegionVar: "uk", "HOSTNAME": "a"}, map[string]bool{"A": true, "HOSTNAME": true}) |
| 185 | if diffs := CompareEnv(src, same, false, false); len(diffs) != 0 { |
| 186 | t.Fatalf("the same instance HOSTNAME: %v", diffs) |
| 187 | } |
| 188 | other := ReportLaunch(key, map[string]string{"A": "1", RegionVar: "uk", "HOSTNAME": "b"}, map[string]bool{"A": true, "HOSTNAME": true}) |
| 189 | if diffs := CompareEnv(src, other, false, false); len(diffs) != 1 || diffs[0].Name != "HOSTNAME" || diffs[0].Kind != "differs" { |
| 190 | t.Fatalf("another instance HOSTNAME: %v", diffs) |
| 191 | } |
| 192 | inherited := ReportLaunch(key, map[string]string{"A": "1", RegionVar: "uk", "HOSTNAME": "box"}, map[string]bool{"A": true}) |
| 193 | if diffs := CompareEnv(src, inherited, false, false); len(diffs) != 1 || diffs[0].Kind != "differs" { |
| 194 | t.Fatalf("the instance's HOSTNAME against the box's: %v", diffs) |
| 195 | } |
| 196 | boxSrc := ReportLaunch(key, map[string]string{"A": "1", RegionVar: "ie", "HOSTNAME": "x"}, map[string]bool{"A": true}) |
| 197 | if diffs := CompareEnv(boxSrc, inherited, false, false); len(diffs) != 0 { |
| 198 | t.Fatalf("two boxes' own HOSTNAMEs: %v", diffs) |
| 199 | } |
| 200 | added := ReportLaunch(key, map[string]string{"A": "1", RegionVar: "uk", "HOSTNAME": "b"}, map[string]bool{"A": true, "HOSTNAME": true}) |
| 201 | if diffs := CompareEnv(ReportLaunch(key, map[string]string{"A": "1", RegionVar: "ie"}, nil), added, false, false); len(diffs) != 1 || diffs[0].Kind != "extra" { |
| 202 | t.Fatalf("a target-only instance HOSTNAME: %v", diffs) |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | func TestEnvReportClassesAndNotes(t *testing.T) { |
| 207 | for name, want := range map[string]string{ |
| 208 | "CARLOS_REGION": "region", "CARLOS_CONTROL_SOCKET": "layout", "CARLOS_PURGE": "advisory", |
| 209 | "INVOCATION_ID": "box", "JOURNAL_STREAM": "box", "HOSTNAME": "box", "PWD": "box", "OLDPWD": "box", "SHLVL": "box", "_": "box", |
| 210 | "DATABASE_URL": "equal", "CARLOS_ADMIN_TOKEN": "equal", |
| 211 | } { |
| 212 | if got := Class(name); got != want { |
| 213 | t.Errorf("Class(%q) = %q, want %q", name, got, want) |
| 214 | } |
| 215 | } |
| 216 | if len(LayoutVars) != 1 || !LayoutVars["CARLOS_CONTROL_SOCKET"] || len(AdvisoryVars) != 1 || !AdvisoryVars["CARLOS_PURGE"] { |
| 217 | t.Fatalf("layout %v advisory %v", LayoutVars, AdvisoryVars) |
| 218 | } |
| 219 | for _, k := range []string{"missing", "extra", "differs", "region-missing", "region-same", "region-present", "layout-missing", "layout-present"} { |
| 220 | if (EnvDiff{"X", k}).Note() { |
| 221 | t.Errorf("%s is a note", k) |
| 222 | } |
| 223 | } |
| 224 | if !(EnvDiff{"X", "advisory-differs"}).Note() { |
| 225 | t.Error("advisory-differs is not a note") |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | func TestCompareEnvNestedLayout(t *testing.T) { |
| 230 | key := []byte("0123456789abcdef0123456789abcdef") |
| 231 | src := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "ie"}) |
| 232 | tgt := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "uk", "CARLOS_CONTROL_SOCKET": "/run/y"}) |
| 233 | // T3's "present iff the flat layout provides it": a layout variable |
| 234 | // only the target carries is a diff on a non-flat landing, and |
| 235 | // nothing on a flat one. |
| 236 | if diffs := CompareEnv(src, tgt, false, false); len(diffs) != 1 || diffs[0].Name != "CARLOS_CONTROL_SOCKET" || diffs[0].Kind != "layout-present" { |
| 237 | t.Fatalf("target-only layout var, non-flat: %v", diffs) |
| 238 | } |
| 239 | if diffs := CompareEnv(src, tgt, true, false); len(diffs) != 0 { |
| 240 | t.Fatalf("target-only layout var, flat: %v", diffs) |
| 241 | } |
| 242 | src2 := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "ie", "CARLOS_CONTROL_SOCKET": "/run/x"}) |
| 243 | if diffs := CompareEnv(src2, tgt, false, false); len(diffs) != 1 || diffs[0].Kind != "layout-present" { |
| 244 | t.Fatalf("layout-present: %v", diffs) |
| 245 | } |
| 246 | // neither side carries it, non-flat: clean |
| 247 | none := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "uk"}) |
| 248 | if diffs := CompareEnv(src, none, false, false); len(diffs) != 0 { |
| 249 | t.Fatalf("no layout var anywhere, non-flat: %v", diffs) |
| 250 | } |
| 251 | // the advisory exception holds: a target-only CARLOS_PURGE is a note |
| 252 | purge := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "uk", "CARLOS_PURGE": "header"}) |
| 253 | if diffs := CompareEnv(src, purge, false, false); len(diffs) != 1 || !diffs[0].Note() { |
| 254 | t.Fatalf("target-only purge, non-flat: %v", diffs) |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | // T3's home rule (home part 2, Review Focus 2): a home target sets no |
| 259 | // CARLOS_REGION (agentOwnedVars adds it only when the box has a region), so |
| 260 | // absent is no diff; a target in home that does set one is not the home |
| 261 | // box, and fails region-present. The same pair compared as a named target |
| 262 | // keeps today's region-missing. |
| 263 | func TestCompareEnvHomeTargetSetsNoRegion(t *testing.T) { |
| 264 | key := []byte("0123456789abcdef0123456789abcdef") |
| 265 | src := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "uk"}) |
| 266 | noRegion := ReportEnv(key, map[string]string{"A": "1"}) |
| 267 | if diffs := CompareEnv(src, noRegion, false, true); len(diffs) != 0 { |
| 268 | t.Fatalf("home target without a region: %v", diffs) |
| 269 | } |
| 270 | if diffs := CompareEnv(src, noRegion, false, false); len(diffs) != 1 || diffs[0].Name != RegionVar || diffs[0].Kind != "region-missing" { |
| 271 | t.Fatalf("named target without a region: %v", diffs) |
| 272 | } |
| 273 | ie := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "ie"}) |
| 274 | if diffs := CompareEnv(src, ie, false, true); len(diffs) != 1 || diffs[0].Name != RegionVar || diffs[0].Kind != "region-present" { |
| 275 | t.Fatalf("home target with a region: %v", diffs) |
| 276 | } |
| 277 | // the source's own region value on a home target: present, not same |
| 278 | uk := ReportEnv(key, map[string]string{"A": "1", "CARLOS_REGION": "uk"}) |
| 279 | if diffs := CompareEnv(src, uk, false, true); len(diffs) != 1 || diffs[0].Kind != "region-present" { |
| 280 | t.Fatalf("home target with the source's region: %v", diffs) |
| 281 | } |
| 282 | // a source without a region (home to home, which the door refuses; |
| 283 | // T3 does not rely on that): absent on both sides is clean, a |
| 284 | // target-only region is still region-present |
| 285 | srcHome := ReportEnv(key, map[string]string{"A": "1"}) |
| 286 | if diffs := CompareEnv(srcHome, noRegion, false, true); len(diffs) != 0 { |
| 287 | t.Fatalf("no region on either side, home target: %v", diffs) |
| 288 | } |
| 289 | if diffs := CompareEnv(srcHome, ie, false, true); len(diffs) != 1 || diffs[0].Name != RegionVar || diffs[0].Kind != "region-present" { |
| 290 | t.Fatalf("target-only region, home target: %v", diffs) |
| 291 | } |
| 292 | // the rest of T3 is unchanged by targetHome |
| 293 | drift := ReportEnv(key, map[string]string{"A": "2", "EXTRA": "x"}) |
| 294 | kinds := map[string]string{} |
| 295 | for _, d := range CompareEnv(src, drift, false, true) { |
| 296 | kinds[d.Name] = d.Kind |
| 297 | } |
| 298 | if len(kinds) != 2 || kinds["A"] != "differs" || kinds["EXTRA"] != "extra" { |
| 299 | t.Fatalf("home target drift: %v", kinds) |
| 300 | } |
| 301 | if (EnvDiff{RegionVar, "region-present"}).Note() { |
| 302 | t.Fatal("region-present is a note") |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | // A named target's T3 region rule is the one before home part 2, with |
| 307 | // targetHome false at every call: the target must set its own region, |
| 308 | // different from the source's; a target-only region (a move out of home) |
| 309 | // is no diff. |
| 310 | func TestNamedTargetT3Unchanged(t *testing.T) { |
| 311 | key := []byte("0123456789abcdef0123456789abcdef") |
| 312 | ie := map[string]string{"A": "1", "CARLOS_REGION": "ie"} |
| 313 | uk := map[string]string{"A": "1", "CARLOS_REGION": "uk"} |
| 314 | none := map[string]string{"A": "1"} |
| 315 | for _, tc := range []struct { |
| 316 | name string |
| 317 | src, tgt map[string]string |
| 318 | want string |
| 319 | }{ |
| 320 | {"named to named", ie, uk, ""}, |
| 321 | {"same region", ie, ie, "region-same"}, |
| 322 | {"target sets none", ie, none, "region-missing"}, |
| 323 | {"out of home", none, uk, ""}, |
| 324 | {"neither sets one", none, none, ""}, |
| 325 | } { |
| 326 | diffs := CompareEnv(ReportEnv(key, tc.src), ReportEnv(key, tc.tgt), false, false) |
| 327 | got := "" |
| 328 | if len(diffs) > 1 || (len(diffs) == 1 && diffs[0].Name != RegionVar) { |
| 329 | t.Fatalf("%s: %v", tc.name, diffs) |
| 330 | } |
| 331 | if len(diffs) == 1 { |
| 332 | got = diffs[0].Kind |
| 333 | } |
| 334 | if got != tc.want { |
| 335 | t.Errorf("%s: %q, want %q", tc.name, got, tc.want) |
| 336 | } |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | func TestReportEnvIsDeterministicAndDigestCoversNamesAndValues(t *testing.T) { |
| 341 | key := []byte("0123456789abcdef0123456789abcdef") |
| 342 | a := ReportEnv(key, map[string]string{"A": "1", "B": "2"}) |
| 343 | b := ReportEnv(key, map[string]string{"B": "2", "A": "1"}) |
| 344 | if a.Digest != b.Digest || a.V != EnvReportVersion || !CurrentEnvReport(a) || !strings.HasPrefix(a.Digest, "env2:sha256:") { |
| 345 | t.Fatalf("%v %v", a, b) |
| 346 | } |
| 347 | // the mac binds the name: the same value under another name differs |
| 348 | c := ReportEnv(key, map[string]string{"A": "2", "B": "1"}) |
| 349 | if c.Digest == a.Digest || c.Vars["A"] == a.Vars["B"] { |
| 350 | t.Fatal("the mac does not bind the name") |
| 351 | } |
| 352 | // name/value boundary: "AB"+"" is not "A"+"B" |
| 353 | if ReportEnv(key, map[string]string{"AB": ""}).Vars["AB"] == ReportEnv(key, map[string]string{"A": "B"}).Vars["A"] { |
| 354 | t.Fatal("name and value run together") |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | func TestReportKeyFromSecrets(t *testing.T) { |
| 359 | raw := make([]byte, 32) |
| 360 | for i := range raw { |
| 361 | raw[i] = byte(i + 1) |
| 362 | } |
| 363 | good := base64.StdEncoding.EncodeToString(raw) |
| 364 | k1, err := ReportKeyFromSecrets(good) |
| 365 | if err != nil || len(k1) != 32 { |
| 366 | t.Fatalf("%v %d", err, len(k1)) |
| 367 | } |
| 368 | k2, _ := ReportKeyFromSecrets(good) |
| 369 | if string(k1) != string(k2) { |
| 370 | t.Fatal("not deterministic") |
| 371 | } |
| 372 | if string(k1) == string(raw) { |
| 373 | t.Fatal("the report key is the raw secret") |
| 374 | } |
| 375 | raw[0] ^= 1 |
| 376 | k3, err := ReportKeyFromSecrets(base64.StdEncoding.EncodeToString(raw)) |
| 377 | if err != nil || string(k3) == string(k1) { |
| 378 | t.Fatalf("key does not depend on the secret: %v", err) |
| 379 | } |
| 380 | for name, in := range map[string]string{ |
| 381 | "malformed base64": "not base64!!", |
| 382 | "empty": "", |
| 383 | "short": base64.StdEncoding.EncodeToString(raw[:31]), |
| 384 | "long": base64.StdEncoding.EncodeToString(append(append([]byte{}, raw...), 0)), |
| 385 | } { |
| 386 | if k, err := ReportKeyFromSecrets(in); err == nil || k != nil { |
| 387 | t.Errorf("%s: key %v err %v", name, k, err) |
| 388 | } else if strings.Contains(err.Error(), in) && in != "" { |
| 389 | t.Errorf("%s: the error echoes the input: %v", name, err) |
| 390 | } |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | // TestEnvReportVersionTwo (fix round 3): a report is version 2 and its |
| 395 | // digest is a v2 pin. A v1 report, or a v1 pin in either v1 form (main's |
| 396 | // whole-env digest, f4f51ba6's digest without box variables), is not |
| 397 | // current, and no v1 form of the same env equals the v2 pin. The local |
| 398 | // digest keeps its own form. |
| 399 | func TestEnvReportVersionTwo(t *testing.T) { |
| 400 | key := []byte("0123456789abcdef0123456789abcdef") |
| 401 | env := map[string]string{"A": "1", "HOSTNAME": "box"} |
| 402 | r := ReportEnv(key, env) |
| 403 | if r.V != 2 || !CurrentEnvReport(r) || !CurrentEnvPin(r.Digest) { |
| 404 | t.Fatalf("not a v2 report: %+v", r) |
| 405 | } |
| 406 | old := r |
| 407 | old.V = 1 |
| 408 | if CurrentEnvReport(old) { |
| 409 | t.Fatal("a v1 report is current") |
| 410 | } |
| 411 | for _, pin := range []string{"", "sha256:" + strings.TrimPrefix(r.Digest, "env2:sha256:"), LocalDigest(key, env), "report"} { |
| 412 | if CurrentEnvPin(pin) { |
| 413 | t.Errorf("%q is a current pin", pin) |
| 414 | } |
| 415 | if pin == r.Digest { |
| 416 | t.Errorf("a v1 form %q equals the v2 pin", pin) |
| 417 | } |
| 418 | } |
| 419 | if !strings.HasPrefix(LocalDigest(key, env), "sha256:") { |
| 420 | t.Fatal("the local digest changed form") |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | // TestBoxVarsCoverTheMeasuredAgentEnvironment pins the non-CARLOS_ |
| 425 | // variables read from carlos-edge's process on dev and flagship boxes |
| 426 | // (2026-10-20) that differ from box to box: each must be box-owned, or |
| 427 | // the env pin of every move between two boxes fails. |
| 428 | func TestBoxVarsCoverTheMeasuredAgentEnvironment(t *testing.T) { |
| 429 | for _, name := range []string{ |
| 430 | "INVOCATION_ID", "JOURNAL_STREAM", "SYSTEMD_EXEC_PID", "MEMORY_PRESSURE_WATCH", "MEMORY_PRESSURE_WRITE", |
| 431 | "AWS_REGION", "STATUS_BOX_REGION", "PLATFORM_EDGE_IPS", "PLATFORM_APPS_DOMAIN", |
| 432 | "CONSOLE_DENY_DOMAINS", "CONSOLE_HOME_REGION", |
| 433 | } { |
| 434 | if !BoxOwned(name) { |
| 435 | t.Errorf("%s differs per box but is not box-owned", name) |
| 436 | } |
| 437 | } |
| 438 | for _, name := range []string{"HOME", "LANG", "LOGNAME", "PATH", "USER"} { |
| 439 | if BoxOwned(name) { |
| 440 | t.Errorf("%s is the same on every box and must stay pinned", name) |
| 441 | } |
| 442 | } |
| 443 | } |
| 444 | |