Merge branch 'claude/team-key-share-rotate-4b2619'
ci / build and test (push) Successful in 1m33s
ci / android head (push) Failing after 5s
ci / api image (push) Successful in 21s

Two conflicts, and the second is worth recording. main's M4 bullet gained the
Android signing decision while this branch rewrote the M5 line either side of it;
both are kept.

The other is an ADR number collision: two sessions each took 0010, one for vault
key rotation and one for Android distribution, and both are now on main. ADR
numbers are identifiers — "see ADR 0010" appears in code comments as well as in
prose — so leaving two would make every such reference ambiguous. The rotation
ADR landed first and is referenced from crypto.md, the gaps document, ADR 0009
and the sync code; the Android one is referenced from README and android-port.md.
So the later and cheaper one moves: 0010-android-distribution.md is now ADR 0011,
with its title and both references updated. Nothing about either decision changes.
This commit is contained in:
2026-08-04 10:23:46 +02:00
14 changed files with 928 additions and 72 deletions
@@ -169,6 +169,11 @@ public sealed class TeamSharingTests : IAsyncLifetime
teams.Status.ShouldContain("Rotated", customMessage: teams.Status);
teams.Status.ShouldContain("Platform secrets");
// The last act of a rotation is moving what is already stored onto the new key. Proven by the
// bytes in DodoSSH.Client.Sync.Tests; what this asserts is that the shell asks for it at all,
// and says which of the two guarantees the user has ended up with.
teams.Status.ShouldContain("re-sealed under the new key", customMessage: teams.Status);
// Gone entirely, at every generation. A revocation that left the history behind would leave them
// able to read everything written before they went, from a copy of the ciphertext.
server.GenerationsGranted(vaultId, leaving).ShouldBeEmpty();