carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package objstore
2
3import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "testing"
8 "time"
9
10 "github.com/carlosframework/platform/internal/release"
11)
12
13// A seed's mark (Declared.Seed) survives only on a store its own seed
14// granted. Any other first grant of a marked record clears the mark in the
15// same write as the grant block, so a seed's finish can never tear down a
16// store another path made (seeded-instances spec §4 Storage).
17func TestFirstGrantClearsAnotherSeedsMark(t *testing.T) {
18 const seedA, seedB = "sd_aaaaaaaaaaaaaaaaaaaaaaaaaa", "sd_bbbbbbbbbbbbbbbbbbbbbbbbbb"
19 for name, c := range map[string]struct {
20 mark, grantFor, want string
21 }{
22 "an unseeded grant": {seedB, "", ""},
23 "another seed's grant": {seedB, seedA, ""},
24 "the marking seed's grant": {seedB, seedB, seedB},
25 } {
26 t.Run(name, func(t *testing.T) {
27 ctx := context.Background()
28 s := release.NewDirStore(t.TempDir())
29 _, pub := testSealKeypair(t)
30 at := time.Now().UTC().Add(-time.Hour)
31 decl := &Declared{EnvPrefix: DefaultEnvPrefix, At: at, By: "member@example.com", Seed: c.mark}
32 if _, err := PutIn(ctx, s, "bab", "shop", "canary", &Record{Declared: decl}, ""); err != nil {
33 t.Fatal(err)
34 }
35 rec, err := GrantInFor(ctx, s, NewMemProvisioner("eu-west-1"), testDeployment(), pub,
36 "bab", "shop", "canary", "op", GrantSourceOperator, "", c.grantFor, time.Now().UTC())
37 if err != nil {
38 t.Fatal(err)
39 }
40 stored, _, err := GetIn(ctx, s, "bab", "shop", "canary")
41 if err != nil {
42 t.Fatal(err)
43 }
44 for _, r := range []*Record{rec, stored} {
45 if r.Declared.Seed != c.want {
46 t.Fatalf("Declared.Seed = %q, want %q", r.Declared.Seed, c.want)
47 }
48 if r.Declared.By != decl.By || !r.Declared.At.Equal(at) || r.Declared.EnvPrefix != decl.EnvPrefix {
49 t.Fatalf("declaration = %+v, want only the mark changed from %+v", r.Declared, decl)
50 }
51 }
52 })
53 }
54}
55
56// A re-run over a store its seed already granted keeps the mark only when
57// it is that seed's own re-run. An unseeded re-run (an operator grant, a
58// provision, an ordinary create sharing the environment) or another seed's
59// clears it, so the aborted seed's finish cannot tear down a store someone
60// else now holds; its bucket leaks instead, the safe direction.
61func TestGrantRerunClearsAMarkThatIsNotItsOwn(t *testing.T) {
62 const seedA, seedB = "sd_aaaaaaaaaaaaaaaaaaaaaaaaaa", "sd_bbbbbbbbbbbbbbbbbbbbbbbbbb"
63 for name, c := range map[string]struct{ rerunFor, want string }{
64 "the same seed's re-run": {seedB, seedB},
65 "an unseeded re-run": {"", ""},
66 "another seed's re-run": {seedA, ""},
67 } {
68 t.Run(name, func(t *testing.T) {
69 ctx := context.Background()
70 s := release.NewDirStore(t.TempDir())
71 _, pub := testSealKeypair(t)
72 p := NewMemProvisioner("eu-west-1")
73 decl := &Declared{EnvPrefix: DefaultEnvPrefix, At: time.Now().UTC(), By: "member@example.com", Seed: seedB}
74 if _, err := PutIn(ctx, s, "bab", "shop", "canary", &Record{Declared: decl}, ""); err != nil {
75 t.Fatal(err)
76 }
77 first, err := GrantInFor(ctx, s, p, testDeployment(), pub, "bab", "shop", "canary", "op", GrantSourceOperator, "", seedB, time.Now().UTC())
78 if err != nil {
79 t.Fatal(err)
80 }
81 rec, err := GrantInFor(ctx, s, p, testDeployment(), pub, "bab", "shop", "canary", "op", GrantSourceOperator, "", c.rerunFor, time.Now().UTC())
82 if err != nil {
83 t.Fatal(err)
84 }
85 stored, _, err := GetIn(ctx, s, "bab", "shop", "canary")
86 if err != nil {
87 t.Fatal(err)
88 }
89 for _, r := range []*Record{rec, stored} {
90 if r.Declared.Seed != c.want {
91 t.Fatalf("Declared.Seed after the re-run = %q, want %q", r.Declared.Seed, c.want)
92 }
93 if r.Grant == nil || *r.Grant != *first.Grant || r.Provisioned == nil || r.Provisioned.KeyID != first.Provisioned.KeyID {
94 t.Fatalf("re-run changed the estate: grant %+v provisioned %+v, want %+v %+v", r.Grant, r.Provisioned, first.Grant, first.Provisioned)
95 }
96 }
97 })
98 }
99}
100
101// A record with no mark is granted exactly as before: its declaration
102// block comes out byte-identical, and no seed key appears.
103func TestGrantLeavesAnUnmarkedDeclarationAsItWas(t *testing.T) {
104 ctx := context.Background()
105 s := release.NewDirStore(t.TempDir())
106 _, pub := testSealKeypair(t)
107 decl := &Declared{EnvPrefix: "SHOP_FILES", At: time.Now().UTC().Add(-time.Hour), By: "member@example.com"}
108 if _, err := PutIn(ctx, s, "bab", "shop", "canary", &Record{Declared: decl}, ""); err != nil {
109 t.Fatal(err)
110 }
111 before, _ := json.Marshal(decl)
112 if _, err := GrantIn(ctx, s, NewMemProvisioner("eu-west-1"), testDeployment(), pub, "bab", "shop", "canary", "op", GrantSourceOperator, "", time.Now().UTC()); err != nil {
113 t.Fatal(err)
114 }
115 raw, _, err := s.Get(ctx, KeyIn("bab", "shop", "canary"))
116 if err != nil {
117 t.Fatal(err)
118 }
119 var stored struct {
120 Declared json.RawMessage `json:"declared"`
121 }
122 if err := json.Unmarshal(raw, &stored); err != nil {
123 t.Fatal(err)
124 }
125 var compact bytes.Buffer
126 if err := json.Compact(&compact, stored.Declared); err != nil {
127 t.Fatal(err)
128 }
129 if !bytes.Equal(compact.Bytes(), before) {
130 t.Fatalf("declaration after the grant = %s, want %s", compact.Bytes(), before)
131 }
132 if bytes.Contains(raw, []byte(`"seed"`)) {
133 t.Fatalf("record = %s, want no seed key", raw)
134 }
135}
136