cloudflare / cloudflare/cloudflare-os

Deleting a private Context collection permanently locks collaborators out of every workspace that observed it

Open
#326 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
9.9k
Forks
1.2k
Avg merge
1d 20h
Merged PRs (30d)
107

Description

## Summary

When a workspace's agent reads the Context library, the ambient Context gatekeeper records every enabled collection as observed (`observedCollection:` keys written by `ContextObserverTracker`, `packages/gatekeeper-context/src/context-observers.ts`) — including the owner's **private** collections, since `getAgentCatalog()` authorizes an observation over all catalog entries. Collaborator verification (`ContextObserverTracker.addObserver`) then requires each observed collection to pass `ContextVerifier.hasCollectionAccess`, i.e. `owns || isPublic`.

While the private collection exists, a blocked collaborator can be fixed by sharing the collection. But if the owner **deletes** the collection (`deleteSelf()` → `storage.deleteAll()`), the recorded observation stays behind in every workspace's Context gatekeeper DO, and `hasCollectionAccess` now returns `false` for everyone, forever: nobody owns the id anymore and it isn't public. Every collaborator of every workspace that ever observed the collection is permanently locked out with:

> Context — This collaborator does not have access to a Context collection whose data this workspace has read, so they cannot be allowed to observe it.

There is no recovery path in the UI or API: collection ids are server-minted so the collection can't be recreated under the same id, and the `observedCollection:` keys are never pruned.

## Steps to reproduce

1. User A creates a **private** Context collection.
2. User A opens a workspace shared with user B and runs any agent turn (the catalog read records an observation of the private collection in that workspace).
3. User A deletes the collection.
4. User B opens the workspace → the "Verify your access again" dialog fails, permanently.

## Expected

Deleting a collection should not permanently brick collaborator access to workspaces. Once the collection's data no longer exists, there is nothing left to protect beyond what already entered chat history (which collaborators can see regardless).

## Possible fix

Treat a collection whose DO has no metadata (`id` is the `""` storage default — the state `deleteSelf()` leaves behind) as accessible in `ContextVerifier.hasCollectionAccess`:

```ts
if (owns || isPublic) return true;
let collections = this.ctx.exports.ContextCollectionDurableObject;
let meta = await collections.get(collections.idFromName(
domainName(sharingDomain, collectionId))).getMetadata();
return !meta.id;
```

A *live* private collection owned by someone else still has `meta.id` set and keeps blocking as today; an RPC error still fails closed. Alternatives: tombstone deleted ids somewhere, or prune `observedCollection:` entries when the collection disappears.

We hit this in production (a private "roles" collection deleted after a trial) and are running the clause above as a local patch; it unblocks affected workspaces at the next verification.

## Related observation

`getAgentCatalog()` records an observation over **every enabled collection** even when the agent never reads their content, which is what makes the blast radius "every workspace the owner has used since creating the collection". Scoping the catalog observation more narrowly (e.g. only collections actually read) would shrink the footprint of this failure mode.

Contributor guide

Open the contributing guide

Research direction

Start in `packages/gatekeeper-context/src/context-observers.ts` and trace `ContextObserverTracker.addObserver` to `ContextVerifier.hasCollectionAccess`; read how `deleteSelf()` and `getMetadata()` represent a deleted collection. The issue proposes treating missing collection metadata as accessible while preserving the existing fail-closed behavior for RPC errors. Verify that deleted private collections no longer block collaborator verification, while live private collections still do.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
66/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.