Skip to content
Get early access

Rotation

Removing someone’s grant stops the next read. It cannot un-know a value they already read, and it cannot reach the copy they pulled last Tuesday.

So invariant 6 says: revocation implies rotation. Any revoke from an environment that matters offers to rotate, and you should accept.

One atomic server-side transaction:

  1. A fresh environment key is generated on your device.
  2. The payload is re-encrypted under it.
  3. The entire grant set is replaced — every remaining member gets the new key wrapped to their public key.
  4. The environment’s key epoch increments.

All of it, or none of it. There is no window where the payload is new and the grants are old.

The epoch increment is what makes stale keys detectable rather than mysteriously broken: a client holding a cached key from the previous epoch knows it, and says so.

Payload history from before the rotation becomes unreadable. Not withheld — unreadable, because the key that decrypted it no longer exists anywhere.

That is the direct consequence of revocation being real. A design where old versions stayed readable would be a design where the old key stayed alive somewhere, which is the thing you were trying to end.

Everyone else re-pulls transparently at their next sync. Anything already running does not: cendarum run injected a snapshot at spawn time, and a rotation does not reach into a live process. Restart it.

This is the part people miss.

Rotating in Cendarum replaces the key that encrypts your secrets. It does not change the secrets themselves. If a departing contractor knew your Stripe key, they still know your Stripe key — rotating the environment means they cannot read the next one.

So: rotate the environment and rotate the underlying credential at whoever issued it. Cendarum can make the second one un-learnable going forward; only your provider can invalidate the first.

If someone writes to the environment between your decision and your rotation, the rotation stops and asks rather than retrying.

That is deliberate. You chose the post-rotation member set against a snapshot; a silent retry over moved state could re-grant someone who was concurrently added, or drop someone who was. Rotation is rare and human-driven, so the cost of a manual re-check is low and the cost of getting it wrong is high.

Anyone with a write grant, because rotation cryptographically requires the current key and only grant-holders have it. An admin without a grant cannot rotate.

This has an honest consequence, and it is in the threat model: a write-grant member can lock everyone out — including owners — by rotating and handing out a wrapped key nobody can open. The server cannot detect that, because detecting it would mean reading a wrapped key.

What exists instead: the clean version of the attack is blocked, so a lockout is loud rather than silent, and every rotation writes an audit row with a name on it. There is no cryptographic mitigation, and on a server that cannot read there cannot be one. A write grant is already trust to re-key — which is worth remembering when you grant one.

If you revoke without rotating, the app shows a “rotation recommended” state. Be aware that this prompt does not currently survive an app restart — the local file format is frozen at v1 and adding a durable flag is a format change. The recommendation reappears the next time you look at the member list, and rotation is available at any time, but don’t rely on the banner to remind you tomorrow.