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.