Rotation
Revoking is not enough
Section titled “Revoking is not enough”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.
What rotation does
Section titled “What rotation does”One atomic server-side transaction:
- A fresh environment key is generated on your device.
- The payload is re-encrypted under it.
- The entire grant set is replaced — every remaining member gets the new key wrapped to their public key.
- 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.
What it costs
Section titled “What it costs”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.
Also rotate the actual credential
Section titled “Also rotate the actual credential”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.
When it conflicts
Section titled “When it conflicts”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.
Who can rotate
Section titled “Who can rotate”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.
A note on the prompt
Section titled “A note on the prompt”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.