How do local deletes work when a Sync Gateway account loses access to a Collection?

Context

Suppose I have a collection, Foo, that is set up to sync via Capella Sync Gateway. The following sequence of events takes place:

  1. A user authenticates with Sync Gateway. His account has the correct role assigned, so all Foo documents successfully sync down to his local database. The user quits my app and the sync session ends.
  2. The same user, with the same local database, now authenticates with Sync Gateway, but uses a different account that does NOT have the correct role assigned (no access to Foo), so Couchbase immediately deletes all Foo documents from the user’s local database, since he’s no longer authorized to access them. The user quits my app and the sync session ends.
  3. The same user, with the same local database, now authenticates with Sync Gateway again, but returns to using the first account that does have the correct role assigned.

What happens?

Does the WAL for the local database contain all the deletes that happened in Step 2? And now those deletes are propagated to the cloud when Step 3 occurs?

We have unexpectedly lost documents from our Capella database and I suspect that this sequence of events explains why.

When the Couchbase SDK (Swift in this case) deletes local Foo documents because the logged-in App Endpoint user account does not have permission to access Foo documents, are those deletes recorded like “normal” deletes? Or are they treated specially so that they are not synced to the cloud if the user regains permission to access Foo documents?

@jens @mreiche Are either of you guys able to comment? I just need to know for certain so I can either guard against this in the future or find another cause for the disappearing documents. Thanks!

I don’t know enough about this.

1 Like

I’m pretty sure switching users on the same local database like this is not supported and what you’re observing are side-effects, but I’d like somebody from product or the Couchbase Lite side to confirm this.

I’ve looked into this for a bit. We do purge those documents on Step 2, on pull, on the CBL side. That will be a new revision and so it will be pushed on Step 3 to SG, deleting them. You do have an edge-case here where there are only 2 users and no common docs. But this can get pretty complicated and specific at scale. Without getting into very specifics, you should create 1 database for each app user on login if there isn’t already one associated with that specific user.

This seems like a big foot gun to just leave lying around.

In my case, the user is the same human. Their OIDC account was just misconfigured by IT such that it didn’t include a roles claim in the JWT. So the Couchbase account that got created didn’t have access to any Collections and the user saw an empty app.

And consider shared Macs. Why would I want to download the same 6GB+ database (which takes 45 minutes!) for each user account if they’re all accessing the same database? There are no “user-specific” documents in our setup. It’s one big database shared across everyone, like a google doc.

As it stands, all it takes to completely nuke a Capella database is one IT manager incorrectly removing the roles claim from a user’s account at a third-party OIDC service such as Azure. That’s crazy.

There is a HUGE difference between “these documents were deleted because a human expressly deleted them” and “these documents were removed because this human lost access to them”. The sync engine should be aware of that difference and do the right thing.

Or imagine an admin going through the users on the App Endpoint to add permission for new Collections. He accidentally flips an old collection off. The user’s local database deletes all those documents. The admin then fixes the mistake, re-granting permission. BOOM: all those documents are nuked from the cloud instantly.

And there is not (as far as I can tell) any API on the SDKs that lets me tell when a user loses access to a collection. If I had that, at least I could delete the entire local database to stop the corruption from spreading to the cloud if the user is re-granted access.

This “edge-case” is a severe pit waiting to destroy data.

Or consider a user who switches departments at a company. IT goes into Capella and revokes sync access to Collections Foo and Bar, and grants sync access to Baz, consistent with this user’s new job at the company. The collections aren’t user-specific; they’re shared across many users at the company.

Later, after the user’s Mac has synced these changes, the user is returned to the original department. BOOM: all Foo and Bar documents are vaporized. No warnings, no confirmations. You just have to know that restoring sync access after revoking sync access is the same thing as deleting documents.

Granting/revoking access to documents should be completely separate from deleting them on the cloud. It should never be possible to lose data on the cloud just because you changed some access grants!

I’m trying to guard against this data-loss scenario in my app. I need two capabilities from the Swift SDK and I’m not sure they exist:

  1. When I start a Sync Replicator with collections [foo, bar, baz], how can I detect if the replicator refuses to sync one or more of these collections because the user doesn’t have permission?

  2. If a user loses access/permission for any of these collections after the Replicator is running, how do I detect that?

In both cases, I need to completely delete the local database to contain the corruption and force the user to start fresh. We can’t have documents getting deleted on the cloud because access permissions were changed.

That’s a really interesting scenario, and it does sound like it could explain the unexpected document loss you’re seeing.

From my experience with Sync Gateway:

  • When a user no longer has access to a collection or channel, the documents are purged locally (not just flagged deleted). A purge is different from a normal delete—it removes the document entirely from the local database and does not generate a revision that would sync back up.

  • Because of that, in step 2 of your sequence, Couchbase Lite isn’t writing those as standard deletes in the WAL. They’re purges due to authorization, so they shouldn’t propagate to the cloud.

  • When the user logs back in with the account that has access again (step 3), those documents should sync down again from the server, since they still exist in the cloud.

If you’re seeing them disappear from Capella itself, that points to something else happening—possibly a legitimate delete being synced by another client, or role/channel access on the server side causing documents to no longer be in the user’s scope.

It might be worth double-checking your sync function, role mappings, and server logs to see whether a delete revision was ever actually pushed to Capella.