github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/test/sbs_test.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package test 6 7 import "testing" 8 9 // TestTlfNameChangePrivate tests that a file written to a private TLF 10 // with an unresolved writer becomes readable to the resolved writer 11 // after resolution. 12 // 13 // This is the equivalent to the TestSBSSimple docker test. 14 func TestTlfNameChangePrivate(t *testing.T) { 15 test(t, 16 users("alice", "bob", "charlie"), 17 inPrivateTlf("alice,bob,charlie@twitter"), 18 as(alice, 19 mkfile("foo.txt", "hello world"), 20 ), 21 as(bob, 22 read("foo.txt", "hello world"), 23 ), 24 as(charlie, 25 expectError(initRoot(), "charlie does not have read access to directory /keybase/private/alice,bob,charlie@twitter"), 26 noSync(), 27 ), 28 29 addNewAssertion("charlie", "charlie@twitter"), 30 as(alice, 31 // TODO: Ideally, we wouldn't have to do this, 32 // and we'd just wait for a rekey. 33 rekey(), 34 ), 35 36 inPrivateTlfNonCanonical("alice,bob,charlie@twitter", "alice,bob,charlie"), 37 as(alice, 38 read("foo.txt", "hello world"), 39 ), 40 as(bob, 41 read("foo.txt", "hello world"), 42 ), 43 as(charlie, 44 read("foo.txt", "hello world"), 45 ), 46 ) 47 } 48 49 // TestTlfNameChangePrivateWithoutObservation tests that a file 50 // written to a private TLF with an unresolved writer after resolution 51 // is readable to the resolved writer. 52 func TestTlfNameChangePrivateWithoutObservation(t *testing.T) { 53 test(t, 54 users("alice", "bob"), 55 inPrivateTlf("alice,bob@twitter"), 56 as(bob, 57 expectError(initRoot(), "bob does not have read access to directory /keybase/private/alice,bob@twitter"), 58 noSync(), 59 ), 60 61 addNewAssertion("bob", "bob@twitter"), 62 63 inPrivateTlfNonCanonical("alice,bob@twitter", "alice,bob"), 64 as(alice, 65 mkfile("foo.txt", "hello world"), 66 ), 67 as(bob, 68 read("foo.txt", "hello world"), 69 ), 70 ) 71 } 72 73 // TestSBSNewlyResolvedWritersPrivate tests that a resolved writer can 74 // be the first writer to a private TLF with an unresolved assertion. 75 func TestSBSNewlyResolvedWritersPrivate(t *testing.T) { 76 test(t, 77 users("alice", "bob"), 78 inPrivateTlf("alice,bob@twitter"), 79 as(bob, 80 expectError(mkfile("foo.txt", "hello world"), 81 "bob does not have read access to directory /keybase/private/alice,bob@twitter"), 82 noSync(), 83 ), 84 85 addNewAssertion("bob", "bob@twitter"), 86 87 inPrivateTlfNonCanonical("alice,bob@twitter", "alice,bob"), 88 as(bob, 89 mkfile("foo.txt", "hello world"), 90 ), 91 as(alice, 92 read("foo.txt", "hello world"), 93 ), 94 ) 95 } 96 97 // TestTlfNameChangePublic tests that a public TLF with an unresolved 98 // writer becomes writeable by the resolved writer after resolution. 99 // 100 // This is the equivalent to the TestSBSSimplePublic docker test. 101 func TestTlfNameChangePublic(t *testing.T) { 102 test(t, 103 users("alice", "bob", "charlie"), 104 inPublicTlf("alice,charlie@twitter"), 105 as(alice, 106 mkfile("alice.txt", "hello charlie"), 107 ), 108 as(bob, 109 read("alice.txt", "hello charlie"), 110 expectError(mkfile("bob.txt", "hello alice & charlie"), 111 "bob does not have write access to directory /keybase/public/alice,charlie@twitter"), 112 noSync(), 113 ), 114 as(charlie, 115 read("alice.txt", "hello charlie"), 116 expectError(mkfile("charlie.txt", "hello alice"), 117 "charlie does not have write access to directory /keybase/public/alice,charlie@twitter"), 118 noSync(), 119 disableUpdates(), 120 ), 121 122 addNewAssertion("charlie", "charlie@twitter"), 123 as(alice, 124 // TODO: Ideally, we wouldn't have to do this, 125 // and we'd just wait for a rekey. 126 rekey(), 127 ), 128 129 inPublicTlfNonCanonical( 130 "alice,charlie@twitter", "alice,charlie"), 131 as(charlie, 132 mkfile("charlie1.txt", "hello alice1"), 133 ), 134 135 inPublicTlf("alice,charlie"), 136 as(charlie, 137 mkfile("charlie2.txt", "hello alice2"), 138 ), 139 140 inPublicTlfNonCanonical( 141 "alice,charlie@twitter", "alice,charlie"), 142 as(alice, 143 read("charlie1.txt", "hello alice1"), 144 read("charlie2.txt", "hello alice2"), 145 ), 146 as(bob, 147 read("charlie1.txt", "hello alice1"), 148 read("charlie2.txt", "hello alice2"), 149 ), 150 as(charlie, 151 read("charlie1.txt", "hello alice1"), 152 read("charlie2.txt", "hello alice2"), 153 ), 154 155 inPublicTlf("alice,charlie"), 156 as(alice, 157 read("charlie1.txt", "hello alice1"), 158 read("charlie2.txt", "hello alice2"), 159 ), 160 as(bob, 161 read("charlie1.txt", "hello alice1"), 162 read("charlie2.txt", "hello alice2"), 163 ), 164 as(charlie, 165 read("charlie1.txt", "hello alice1"), 166 read("charlie2.txt", "hello alice2"), 167 ), 168 ) 169 } 170 171 // TestTlfNameChangePublicWithoutObservation tests that a public TLF 172 // with an unresolved writer becomes writeable by the resolved writer 173 // after resolution. 174 func TestTlfNameChangePublicWithoutObservation(t *testing.T) { 175 test(t, 176 users("alice", "bob", "charlie"), 177 inPublicTlf("alice,charlie@twitter"), 178 as(charlie, noSync()), // no-op to initialize the SBS folder 179 addNewAssertion("charlie", "charlie@twitter"), 180 181 inPublicTlfNonCanonical( 182 "alice,charlie@twitter", "alice,charlie"), 183 as(alice, 184 mkfile("alice.txt", "hello charlie"), 185 ), 186 as(bob, 187 read("alice.txt", "hello charlie"), 188 ), 189 as(charlie, 190 read("alice.txt", "hello charlie"), 191 ), 192 ) 193 } 194 195 // TestSBSNewlyResolvedWritersPublic tests that a resolved writer can 196 // be the first writer to a public TLF with an unresolved assertion. 197 func TestSBSNewlyResolvedWritersPublic(t *testing.T) { 198 test(t, 199 users("alice", "bob", "charlie"), 200 inPublicTlf("alice,charlie@twitter"), 201 as(charlie, 202 expectError(mkfile("foo.txt", "hello world"), 203 "charlie does not have write access to directory /keybase/public/alice,charlie@twitter"), 204 noSync(), 205 ), 206 207 addNewAssertion("charlie", "charlie@twitter"), 208 209 inPublicTlfNonCanonical( 210 "alice,charlie@twitter", "alice,charlie"), 211 as(charlie, 212 mkfile("charlie.txt", "hello alice"), 213 ), 214 as(alice, 215 read("charlie.txt", "hello alice"), 216 ), 217 as(bob, 218 read("charlie.txt", "hello alice"), 219 ), 220 ) 221 } 222 223 // TODO: Write an equivalent to TestSBSFavorites from the docker 224 // tests. 225 226 // TestSBSExistingWriter tests that a TLF with an unresolved writer 227 // that resolves to an existing writer resolves to the TLF without the 228 // unresolved writer. 229 func TestSBSExistingWriter(t *testing.T) { 230 test(t, 231 users("alice", "bob"), 232 inPrivateTlf("alice,bob,bob@twitter"), 233 as(alice, 234 mkfile("alice.txt", "hello bob"), 235 ), 236 as(bob, 237 mkfile("bob.txt", "hello alice"), 238 read("alice.txt", "hello bob"), 239 ), 240 as(alice, 241 read("bob.txt", "hello alice"), 242 ), 243 244 addNewAssertion("bob", "bob@twitter"), 245 as(alice, 246 // TODO: Ideally, we wouldn't have to do this, 247 // and we'd just wait for a rekey. 248 rekey(), 249 ), 250 251 inPrivateTlf("alice,bob"), 252 as(alice, 253 read("alice.txt", "hello bob"), 254 read("bob.txt", "hello alice"), 255 ), 256 as(bob, 257 read("alice.txt", "hello bob"), 258 read("bob.txt", "hello alice"), 259 ), 260 261 inPrivateTlfNonCanonical("alice,bob,bob@twitter", "alice,bob"), 262 as(alice, 263 read("alice.txt", "hello bob"), 264 read("bob.txt", "hello alice"), 265 ), 266 as(bob, 267 read("alice.txt", "hello bob"), 268 read("bob.txt", "hello alice"), 269 ), 270 ) 271 } 272 273 // TestSBSPromoteReaderToWriter tests that a TLF with an unresolved 274 // writer that resolves to an existing reader resolves to the TLF with 275 // the reader promoted to a writer. 276 func TestSBSPromoteReaderToWriter(t *testing.T) { 277 test(t, 278 users("alice", "bob"), 279 inPrivateTlf("alice,bob@twitter#bob"), 280 as(alice, 281 mkfile("alice.txt", "hello bob"), 282 ), 283 as(bob, 284 read("alice.txt", "hello bob"), 285 expectError(mkfile("bob.txt", "hello alice"), 286 "bob does not have write access to directory /keybase/private/alice,bob@twitter#bob"), 287 noSync(), 288 ), 289 290 addNewAssertion("bob", "bob@twitter"), 291 as(alice, 292 // TODO: Ideally, we wouldn't have to do this, 293 // and we'd just wait for a rekey. 294 rekey(), 295 ), 296 297 inPrivateTlf("alice,bob"), 298 as(alice, 299 read("alice.txt", "hello bob"), 300 ), 301 as(bob, 302 read("alice.txt", "hello bob"), 303 mkfile("bob.txt", "hello alice"), 304 ), 305 as(alice, 306 read("bob.txt", "hello alice"), 307 ), 308 309 inPrivateTlfNonCanonical("alice,bob@twitter#bob", "alice,bob"), 310 as(alice, 311 read("alice.txt", "hello bob"), 312 read("bob.txt", "hello alice"), 313 ), 314 as(bob, 315 read("alice.txt", "hello bob"), 316 read("bob.txt", "hello alice"), 317 ), 318 ) 319 } 320 321 // TestSBSOnlyUnresolvedWriter tests that a TLF with a single 322 // unresolved writer is only usable once that writer becomes resolved. 323 func TestSBSOnlyUnresolvedWriter(t *testing.T) { 324 test(t, 325 users("alice"), 326 inPrivateTlf("alice@twitter"), 327 as(alice, 328 expectError(mkfile("foo.txt", "hello world"), 329 "alice does not have read access to directory /keybase/private/alice@twitter"), 330 noSync(), 331 ), 332 333 addNewAssertion("alice", "alice@twitter"), 334 335 inPrivateTlf("alice"), 336 as(alice, 337 mkfile("foo.txt", "hello world"), 338 ), 339 340 inPrivateTlfNonCanonical("alice@twitter", "alice"), 341 as(alice, 342 read("foo.txt", "hello world"), 343 ), 344 ) 345 } 346 347 // TestSBSMultipleResolutions tests that a folder with multiple 348 // unresolved writers behaves as expected when each unresolved writer 349 // is resolved one at a time. 350 func TestSBSMultipleResolutions(t *testing.T) { 351 test(t, 352 users("alice", "bob", "charlie"), 353 inPrivateTlf("alice,bob@twitter,charlie@twitter"), 354 as(alice, 355 mkfile("alice.txt", "hello bob & charlie"), 356 ), 357 as(bob, 358 expectError(initRoot(), "bob does not have read access to directory /keybase/private/alice,bob@twitter,charlie@twitter"), 359 noSync(), 360 ), 361 as(charlie, 362 expectError(initRoot(), "charlie does not have read access to directory /keybase/private/alice,bob@twitter,charlie@twitter"), 363 noSync(), 364 ), 365 366 addNewAssertion("bob", "bob@twitter"), 367 as(alice, 368 // TODO: Ideally, we wouldn't have to do this, 369 // and we'd just wait for a rekey. 370 rekey(), 371 ), 372 373 inPrivateTlfNonCanonical("alice,bob@twitter,charlie@twitter", "alice,bob,charlie@twitter"), 374 as(bob, 375 read("alice.txt", "hello bob & charlie"), 376 mkfile("bob1.txt", "hello alice & charlie"), 377 ), 378 as(alice, 379 read("alice.txt", "hello bob & charlie"), 380 read("bob1.txt", "hello alice & charlie"), 381 ), 382 as(charlie, 383 expectError(initRoot(), "charlie does not have read access to directory /keybase/private/alice,bob,charlie@twitter"), 384 noSync(), 385 ), 386 387 inPrivateTlf("alice,bob,charlie@twitter"), 388 as(bob, 389 read("alice.txt", "hello bob & charlie"), 390 read("bob1.txt", "hello alice & charlie"), 391 mkfile("bob2.txt", "hello alice & charlie"), 392 ), 393 as(alice, 394 read("alice.txt", "hello bob & charlie"), 395 read("bob1.txt", "hello alice & charlie"), 396 read("bob2.txt", "hello alice & charlie"), 397 ), 398 as(charlie, 399 expectError(initRoot(), "charlie does not have read access to directory /keybase/private/alice,bob,charlie@twitter"), 400 noSync(), 401 ), 402 403 addNewAssertion("charlie", "charlie@twitter"), 404 as(bob, 405 // TODO: Ideally, we wouldn't have to do this, 406 // and we'd just wait for a rekey. 407 rekey(), 408 ), 409 410 inPrivateTlfNonCanonical("alice,bob@twitter,charlie@twitter", "alice,bob,charlie"), 411 as(charlie, 412 read("alice.txt", "hello bob & charlie"), 413 read("bob1.txt", "hello alice & charlie"), 414 read("bob2.txt", "hello alice & charlie"), 415 mkfile("charlie1.txt", "hello alice & bob"), 416 ), 417 as(alice, 418 read("alice.txt", "hello bob & charlie"), 419 read("bob1.txt", "hello alice & charlie"), 420 read("bob2.txt", "hello alice & charlie"), 421 read("charlie1.txt", "hello alice & bob"), 422 ), 423 as(bob, 424 read("alice.txt", "hello bob & charlie"), 425 read("bob1.txt", "hello alice & charlie"), 426 read("bob2.txt", "hello alice & charlie"), 427 read("charlie1.txt", "hello alice & bob"), 428 ), 429 430 inPrivateTlf("alice,bob,charlie"), 431 as(charlie, 432 read("alice.txt", "hello bob & charlie"), 433 read("bob1.txt", "hello alice & charlie"), 434 read("bob2.txt", "hello alice & charlie"), 435 read("charlie1.txt", "hello alice & bob"), 436 mkfile("charlie2.txt", "hello alice & bob"), 437 ), 438 as(alice, 439 read("alice.txt", "hello bob & charlie"), 440 read("bob1.txt", "hello alice & charlie"), 441 read("bob2.txt", "hello alice & charlie"), 442 read("charlie1.txt", "hello alice & bob"), 443 read("charlie2.txt", "hello alice & bob"), 444 ), 445 as(bob, 446 read("alice.txt", "hello bob & charlie"), 447 read("bob1.txt", "hello alice & charlie"), 448 read("bob2.txt", "hello alice & charlie"), 449 read("charlie1.txt", "hello alice & bob"), 450 read("charlie2.txt", "hello alice & bob"), 451 ), 452 ) 453 } 454 455 // TestSBSConflicts tests that different folders with unresolved users 456 // that get resolved to the same one don't get merged, but that one is 457 // chosen and the others pick up a conflict marker. 458 func TestSBSConflicts(t *testing.T) { 459 test(t, 460 users("alice", "bob", "charlie"), 461 inPrivateTlf("alice,bob,charlie@twitter"), 462 as(alice, 463 mkfile("alice1.txt", "hello bob & charlie"), 464 ), 465 as(bob, 466 read("alice1.txt", "hello bob & charlie"), 467 ), 468 as(charlie, 469 expectError(initRoot(), "charlie does not have read access to directory /keybase/private/alice,bob,charlie@twitter"), 470 noSync(), 471 ), 472 473 inPrivateTlf("alice,bob@twitter,charlie@twitter"), 474 as(alice, 475 mkfile("alice2.txt", "hello bob & charlie"), 476 ), 477 as(bob, 478 expectError(initRoot(), "bob does not have read access to directory /keybase/private/alice,bob@twitter,charlie@twitter"), 479 noSync(), 480 ), 481 as(charlie, 482 expectError(initRoot(), "charlie does not have read access to directory /keybase/private/alice,bob@twitter,charlie@twitter"), 483 noSync(), 484 ), 485 486 inPrivateTlf("alice,bob,charlie"), 487 as(alice, 488 mkfile("alice3.txt", "hello bob & charlie"), 489 ), 490 as(bob, 491 read("alice3.txt", "hello bob & charlie"), 492 ), 493 as(charlie, 494 read("alice3.txt", "hello bob & charlie"), 495 ), 496 497 addNewAssertion("bob", "bob@twitter"), 498 addNewAssertion("charlie", "charlie@twitter"), 499 as(alice, 500 // TODO: Ideally, we wouldn't have to do this, 501 // and we'd just wait for a rekey. 502 rekey(), 503 ), 504 505 // TODO: Test that alice's favorites are updated. 506 507 // TODO: Test that the three folders are resolved with 508 // conflict markers. This will require changes to 509 // MDServerLocal. 510 ) 511 } 512 513 // TODO: When we implement automatic rekey for DSL tests, write 514 // equivalents of TestSBSOfflineDeviceComesOnline{Private,Public} from 515 // the docker tests.