Backend: app-owned space membership store in the encrypted state-backend #213

Closed
opened 2026-08-13 15:17:07 +00:00 by Cordy · 1 comment
Owner

Parent: #211.

A Cairn-owned membership object per app-created space: { space, owner, members: [{user, role}] }, persisted under .cairn-state/ (age-encrypted, like shares.json/holds.json) — the source of truth for spaces Cairn creates, independent of any IdP.

Scope

  • New store (follow the shares/holds pattern): create space, get, list-for-user, set-member (write|read), remove-member, delete space; owner is set at create.
  • Roles mirror existing space semantics (write/read, -ro read-only parity).
  • No IdP calls. Works identically under local/oidc/ldap auth and any key custody.
  • Validation: reuse validSpaceName; refuse names colliding with an existing IdP group the user is in (avoid two spaces of the same name).

Acceptance: unit tests for CRUD + role transitions + persistence round-trip through the state-backend; owner cannot be demoted/removed; concurrent writers safe (single-writer instance assumption holds).

TDD from the start.

Parent: #211. A Cairn-owned membership object per app-created space: `{ space, owner, members: [{user, role}] }`, persisted under `.cairn-state/` (age-encrypted, like `shares.json`/`holds.json`) — the source of truth for spaces Cairn creates, independent of any IdP. **Scope** - New store (follow the shares/holds pattern): create space, get, list-for-user, set-member (write|read), remove-member, delete space; owner is set at create. - Roles mirror existing space semantics (`write`/`read`, `-ro` read-only parity). - No IdP calls. Works identically under `local`/`oidc`/`ldap` auth and any key custody. - Validation: reuse `validSpaceName`; refuse names colliding with an existing IdP group the user is in (avoid two spaces of the same name). **Acceptance:** unit tests for CRUD + role transitions + persistence round-trip through the state-backend; owner cannot be demoted/removed; concurrent writers safe (single-writer instance assumption holds). TDD from the start.
Author
Owner

Done — internal/spacestore merged (PR #220). Owner + members per Cairn space, persisted through statestore (age-encrypted in the backend like shares/holds), atomic clone-then-commit, no IdP calls. CRUD + RoleFor/SpacesForUser/List; owner is always write and cannot be demoted or removed. CI green (vet + tests including the round-trip, both-arch build). Next: #214 wires it into the scope driver.

Done — `internal/spacestore` merged (PR #220). Owner + members per Cairn space, persisted through `statestore` (age-encrypted in the backend like shares/holds), atomic clone-then-commit, no IdP calls. CRUD + `RoleFor`/`SpacesForUser`/`List`; owner is always write and cannot be demoted or removed. CI green (vet + tests including the round-trip, both-arch build). Next: #214 wires it into the scope driver.
Cordy closed this issue 2026-08-13 16:14:15 +00:00
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#213
No description provided.