proxy_test.gno
7.20 Kb · 220 lines
1package config
2
3import (
4 "testing"
5
6 "chain"
7
8 "gno.land/p/nt/uassert/v0"
9)
10
11// v2Path is a plausible next version. Nothing is deployed there; the tests
12// only need the address the path resolves to, which is what an incoming
13// relayed call is actually compared against.
14const v2Path = "gno.land/r/moul/config/v2"
15
16func v2Addr() address { return chain.PackageAddress(v2Path) }
17
18func TestAllowAndRevokeProxy(cur realm, t *testing.T) {
19 resetSettings()
20 uassert.Equal(t, 0, len(ListProxies()))
21 uassert.False(t, IsProxy(v2Addr()))
22
23 testing.SetRealm(testing.NewUserRealm(originAddr))
24 AllowProxy(cross(cur), v2Path)
25
26 uassert.True(t, IsProxy(v2Addr()))
27 uassert.Equal(t, 1, len(ListProxies()))
28 uassert.Equal(t, v2Path, ListProxies()[0])
29
30 testing.SetRealm(testing.NewUserRealm(originAddr))
31 RevokeProxy(cross(cur), v2Path)
32 uassert.False(t, IsProxy(v2Addr()))
33 uassert.Equal(t, 0, len(ListProxies()))
34}
35
36func TestProxyRegistrationIsManagerOnly(cur realm, t *testing.T) {
37 resetSettings()
38
39 testing.SetRealm(testing.NewUserRealm(nonManagerAddr))
40 uassert.AbortsContains(t, cur, "unauthorized", func() {
41 AllowProxy(cross(cur), v2Path)
42 })
43 uassert.False(t, IsProxy(v2Addr()), "a rejected registration leaves nothing behind")
44}
45
46// TestProxyPathMustBeASiblingVersion keeps a fat-fingered AllowProxy from
47// becoming a standing write grant to an unrelated realm.
48func TestProxyPathMustBeASiblingVersion(cur realm, t *testing.T) {
49 resetSettings()
50
51 bad := []string{
52 "gno.land/r/someone/evil",
53 "gno.land/r/moul/home",
54 "gno.land/r/moul/configuration/v2", // prefix-adjacent, not a sibling
55 "gno.land/r/moul/config/v", // no number
56 "gno.land/r/moul/config/vnext",
57 "gno.land/r/moul/config/v2/sub",
58 "",
59 }
60 for _, path := range bad {
61 testing.SetRealm(testing.NewUserRealm(originAddr))
62 uassert.AbortsContains(t, cur, "must be a later version", func() {
63 AllowProxy(cross(cur), path)
64 })
65 }
66 uassert.Equal(t, 0, len(ListProxies()))
67}
68
69func TestRevokeUnknownProxyAborts(cur realm, t *testing.T) {
70 resetSettings()
71 testing.SetRealm(testing.NewUserRealm(originAddr))
72 uassert.AbortsWithMessage(t, cur, "no such proxy: "+v2Path, func() {
73 RevokeProxy(cross(cur), v2Path)
74 })
75}
76
77// TestRelayNeedsRegistration is the first of the relay's two checks: without
78// it, any realm could claim to be acting for any principal.
79func TestRelayNeedsRegistration(cur realm, t *testing.T) {
80 resetSettings()
81
82 testing.SetRealm(testing.NewCodeRealm(v2Path))
83 uassert.AbortsContains(t, cur, "not a registered proxy", func() {
84 SetAs(cross(cur), originAddr, "some.key", "value")
85 })
86 uassert.Equal(t, 0, Size())
87}
88
89// TestRelayStillChecksThePrincipal is the second check, and the reason a proxy
90// is not simply an unconditional bypass: the member list stays the single
91// answer to "who may change config", for every version at once.
92func TestRelayStillChecksThePrincipal(cur realm, t *testing.T) {
93 resetSettings()
94 testing.SetRealm(testing.NewUserRealm(originAddr))
95 AllowProxy(cross(cur), v2Path)
96
97 testing.SetRealm(testing.NewCodeRealm(v2Path))
98 uassert.AbortsContains(t, cur, "unauthorized", func() {
99 SetAs(cross(cur), nonManagerAddr, "some.key", "value")
100 })
101 uassert.Equal(t, 0, Size())
102
103 // An empty principal is not a wildcard.
104 testing.SetRealm(testing.NewCodeRealm(v2Path))
105 uassert.AbortsContains(t, cur, "no principal", func() {
106 SetAs(cross(cur), "", "some.key", "value")
107 })
108}
109
110// TestRelayWritesTheSameState is the property the whole version chain exists
111// for: a write arriving through a later version lands in exactly the store
112// that a direct write lands in, so v1 and v2 readers never disagree.
113func TestRelayWritesTheSameState(cur realm, t *testing.T) {
114 resetSettings()
115 testing.SetRealm(testing.NewUserRealm(originAddr))
116 AllowProxy(cross(cur), v2Path)
117
118 testing.SetRealm(testing.NewCodeRealm(v2Path))
119 SetAs(cross(cur), originAddr, KeyMygnoscanURL, "https://scan.example.com")
120
121 uassert.Equal(t, "https://scan.example.com", Get(KeyMygnoscanURL))
122 uassert.Equal(t, "https://scan.example.com", MygnoscanURL(),
123 "the typed accessor sees the relayed write too")
124
125 testing.SetRealm(testing.NewCodeRealm(v2Path))
126 UnsetAs(cross(cur), originAddr, KeyMygnoscanURL)
127 uassert.False(t, Has(KeyMygnoscanURL))
128}
129
130// TestRelayValidatesLikeTheDirectPath: a relay is a different door, not a
131// different set of rules. Key shape and value grammar are checked identically.
132func TestRelayValidatesLikeTheDirectPath(cur realm, t *testing.T) {
133 resetSettings()
134 testing.SetRealm(testing.NewUserRealm(originAddr))
135 AllowProxy(cross(cur), v2Path)
136
137 testing.SetRealm(testing.NewCodeRealm(v2Path))
138 uassert.AbortsContains(t, cur, "invalid key", func() {
139 SetAs(cross(cur), originAddr, "Bad Key", "value")
140 })
141
142 testing.SetRealm(testing.NewCodeRealm(v2Path))
143 uassert.AbortsContains(t, cur, "invalid pause value", func() {
144 SetAs(cross(cur), originAddr, KeyPause, "yes")
145 })
146}
147
148// TestRevokedProxyCannotWrite: revocation is the emergency brake on the relay
149// itself, so it has to bite immediately.
150func TestRevokedProxyCannotWrite(cur realm, t *testing.T) {
151 resetSettings()
152 testing.SetRealm(testing.NewUserRealm(originAddr))
153 AllowProxy(cross(cur), v2Path)
154
155 testing.SetRealm(testing.NewCodeRealm(v2Path))
156 SetAs(cross(cur), originAddr, "some.key", "before")
157
158 testing.SetRealm(testing.NewUserRealm(originAddr))
159 RevokeProxy(cross(cur), v2Path)
160
161 testing.SetRealm(testing.NewCodeRealm(v2Path))
162 uassert.AbortsContains(t, cur, "not a registered proxy", func() {
163 SetAs(cross(cur), originAddr, "some.key", "after")
164 })
165 uassert.Equal(t, "before", Get("some.key"))
166}
167
168// TestManagerChangesReachTheRelay is what makes one member list serve every
169// version: adding a manager here works through v2 with no further deploys.
170func TestManagerChangesReachTheRelay(cur realm, t *testing.T) {
171 resetSettings()
172 testing.SetRealm(testing.NewUserRealm(originAddr))
173 AllowProxy(cross(cur), v2Path)
174
175 testing.SetRealm(testing.NewCodeRealm(v2Path))
176 uassert.AbortsContains(t, cur, "unauthorized", func() {
177 SetAs(cross(cur), manager1Addr, "some.key", "value")
178 })
179
180 testing.SetRealm(testing.NewUserRealm(originAddr))
181 uassert.NoError(t, AddManager(cross(cur), manager1Addr))
182
183 testing.SetRealm(testing.NewCodeRealm(v2Path))
184 SetAs(cross(cur), manager1Addr, "some.key", "value")
185 uassert.Equal(t, "value", Get("some.key"))
186}
187
188// ExampleRender_proxies pins the section that only exists once a later version
189// is registered, which is the state this realm spends most of its life NOT in.
190func ExampleRender_proxies() {
191 resetSettings()
192 proxies.Set(v2Path, chain.PackageAddress(v2Path))
193 print(Render(""))
194 // Output:
195 // # gno.land/r/moul/config
196 //
197 // moul's settings, read by his other realms. rev 0 · 0 setting(s)
198 //
199 // ## Settings
200 //
201 // _none set; every reader is on its built-in default_
202 //
203 // ## Pause
204 //
205 // _running; no global pause_
206 //
207 // ## Authority
208 //
209 // `member_authority[g1daexjemfde047h6lta047h6lta047h6ld2pug6]`
210 //
211 // ## Proxies
212 //
213 // Later versions of this realm that may relay a write:
214 //
215 // - `gno.land/r/moul/config/v2`
216 //
217 // ---
218 //
219 // [explorer](https://mygnoscan.moul.p2p.team/realm/r/moul/config/v1) · [source](https://mygnoscan.moul.p2p.team/realm/r/moul/config/v1?tab=source) · [calls](https://mygnoscan.moul.p2p.team/realm/r/moul/config/v1?tab=calls) · [deps](https://mygnoscan.moul.p2p.team/realm/r/moul/config/v1?tab=deps)
220}