oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1package docs
2
3import (
4 "context"
5 "testing"
6)
7
8// readable is the seam sharing adds beside owned. owned answers "whose
9// document is this"; readable answers "who may read it", which is the owner
10// plus anybody holding a grant.
11//
12// owned's own doc comment says the day sharing lands is the day this changes,
13// and TestOwnedScopesByOwner was written to be the test that has to keep
14// passing when it does. It still tests owned, unchanged, and owned still means
15// exactly what it meant. What is new is a second function beside it, so no
16// call site that genuinely wants ownership silently starts accepting grantees.
17func TestReadableIncludesGrantees(t *testing.T) {
18 app, err := NewForTest(t)
19 if err != nil {
20 t.Fatalf("NewForTest: %v", err)
21 }
22 ctx := context.Background()
23 store := app.Store()
24
25 alice, err := store.EnsurePerson(ctx, "alice@example.com")
26 if err != nil {
27 t.Fatalf("EnsurePerson(alice): %v", err)
28 }
29 bob, err := store.EnsurePerson(ctx, "bob@example.com")
30 if err != nil {
31 t.Fatalf("EnsurePerson(bob): %v", err)
32 }
33 carol, err := store.EnsurePerson(ctx, "carol@example.com")
34 if err != nil {
35 t.Fatalf("EnsurePerson(carol): %v", err)
36 }
37
38 doc, err := store.Create(ctx, alice, "Alice's document")
39 if err != nil {
40 t.Fatalf("Create: %v", err)
41 }
42 if err := store.Grant(ctx, alice, doc.Sqid, "bob@example.com", RoleReader); err != nil {
43 t.Fatalf("Grant: %v", err)
44 }
45
46 // Bob reads it because he was granted it.
47 var bobRows []*Document
48 if err := readable(store.db.WithContext(ctx), localActor(bob, "bob@example.com")).Find(&bobRows).Error; err != nil {
49 t.Fatalf("readable(bob): %v", err)
50 }
51 if len(bobRows) != 1 || bobRows[0].ID != doc.ID {
52 t.Errorf("readable(bob) = %d row(s), want exactly Alice's document", len(bobRows))
53 }
54
55 // Alice still reads her own.
56 var aliceRows []*Document
57 if err := readable(store.db.WithContext(ctx), localActor(alice, "alice@example.com")).Find(&aliceRows).Error; err != nil {
58 t.Fatalf("readable(alice): %v", err)
59 }
60 if len(aliceRows) != 1 {
61 t.Errorf("readable(alice) = %d row(s), want 1", len(aliceRows))
62 }
63
64 // Carol was granted nothing and reads nothing. Without this the whole
65 // thing could be a query that returns every row.
66 var carolRows []*Document
67 if err := readable(store.db.WithContext(ctx), localActor(carol, "carol@example.com")).Find(&carolRows).Error; err != nil {
68 t.Fatalf("readable(carol): %v", err)
69 }
70 if len(carolRows) != 0 {
71 t.Errorf("readable(carol) = %d row(s), want 0 — carol holds no grant", len(carolRows))
72 }
73}
74
75// A grant is keyed on the address, not on a people row, so it can be made to
76// somebody who has never signed in. EnsurePerson seeds a sample library on the
77// create branch, so minting a Person for an invitee would hand them six sample
78// documents they never asked for.
79func TestGrantToSomebodyWhoHasNeverSignedIn(t *testing.T) {
80 app, err := NewForTest(t)
81 if err != nil {
82 t.Fatalf("NewForTest: %v", err)
83 }
84 ctx := context.Background()
85 store := app.Store()
86
87 alice, err := store.EnsurePerson(ctx, "alice@example.com")
88 if err != nil {
89 t.Fatalf("EnsurePerson(alice): %v", err)
90 }
91 doc, err := store.Create(ctx, alice, "Alice's document")
92 if err != nil {
93 t.Fatalf("Create: %v", err)
94 }
95
96 if err := store.Grant(ctx, alice, doc.Sqid, "dave@example.com", RoleReader); err != nil {
97 t.Fatalf("Grant to a stranger: %v", err)
98 }
99
100 var people []*Person
101 if err := store.db.WithContext(ctx).Where("email = ?", "dave@example.com").Find(&people).Error; err != nil {
102 t.Fatalf("counting people: %v", err)
103 }
104 if len(people) != 0 {
105 t.Errorf("granting minted a Person row for dave, which would seed him a sample library")
106 }
107
108 // And the grant works the moment he does sign in.
109 dave, err := store.EnsurePerson(ctx, "dave@example.com")
110 if err != nil {
111 t.Fatalf("EnsurePerson(dave): %v", err)
112 }
113 var daveRows []*Document
114 if err := readable(store.db.WithContext(ctx), localActor(dave, "dave@example.com")).Find(&daveRows).Error; err != nil {
115 t.Fatalf("readable(dave): %v", err)
116 }
117 if len(daveRows) != 1 {
118 t.Errorf("readable(dave) = %d row(s), want the document granted before he existed", len(daveRows))
119 }
120}
121
122// Addresses are matched the way EnsurePerson stores them: lowercased and
123// trimmed. A grant made to "Bob@Example.com " must be the grant Bob holds.
124func TestGrantSubjectIsNormalised(t *testing.T) {
125 app, err := NewForTest(t)
126 if err != nil {
127 t.Fatalf("NewForTest: %v", err)
128 }
129 ctx := context.Background()
130 store := app.Store()
131
132 alice, _ := store.EnsurePerson(ctx, "alice@example.com")
133 bob, _ := store.EnsurePerson(ctx, "bob@example.com")
134 doc, err := store.Create(ctx, alice, "Alice's document")
135 if err != nil {
136 t.Fatalf("Create: %v", err)
137 }
138
139 if err := store.Grant(ctx, alice, doc.Sqid, " Bob@Example.COM ", RoleReader); err != nil {
140 t.Fatalf("Grant: %v", err)
141 }
142
143 var rows []*Document
144 if err := readable(store.db.WithContext(ctx), localActor(bob, "bob@example.com")).Find(&rows).Error; err != nil {
145 t.Fatalf("readable(bob): %v", err)
146 }
147 if len(rows) != 1 {
148 t.Errorf("readable(bob) = %d row(s); the grant's address was not normalised", len(rows))
149 }
150}
151
152// An orphaned document — owner_id 0, which 0002_owners.sql writes onto every
153// pre-existing row — stays invisible even if a grant points at it. Three tests
154// already pin that owner 0 matches nothing; a grants clause must not become
155// the way around them.
156func TestReadableKeepsOrphansInvisible(t *testing.T) {
157 app, err := NewForTest(t)
158 if err != nil {
159 t.Fatalf("NewForTest: %v", err)
160 }
161 ctx := context.Background()
162 store := app.Store()
163
164 alice, _ := store.EnsurePerson(ctx, "alice@example.com")
165 bob, _ := store.EnsurePerson(ctx, "bob@example.com")
166 doc, err := store.Create(ctx, alice, "Alice's document")
167 if err != nil {
168 t.Fatalf("Create: %v", err)
169 }
170 if err := store.Grant(ctx, alice, doc.Sqid, "bob@example.com", RoleReader); err != nil {
171 t.Fatalf("Grant: %v", err)
172 }
173
174 // Orphan it after the grant exists.
175 if err := store.db.WithContext(ctx).Model(&Document{}).Where("id = ?", doc.ID).
176 Update("owner_id", 0).Error; err != nil {
177 t.Fatalf("orphaning: %v", err)
178 }
179
180 var rows []*Document
181 if err := readable(store.db.WithContext(ctx), localActor(bob, "bob@example.com")).Find(&rows).Error; err != nil {
182 t.Fatalf("readable(bob): %v", err)
183 }
184 if len(rows) != 0 {
185 t.Errorf("an orphaned document was readable through a grant; owner 0 must match nothing")
186 }
187}
188