Peering admin panel: warn when a receivers list is group-only and no IdP admin client is configured #129

Closed
opened 2026-08-07 00:05:55 +00:00 by Cordy · 1 comment
Owner

Split out of #105 so it survives that issue closing (the same near-miss as #104's notification gap).

The trap (from #123): CanReceive takes groups as a parameter because the recipient is not authenticated — there is no session to read live groups from. The cmd/cairnd wiring passes nil when no IdP admin client is configured. So on such an instance, a group-only receivers allow-list matches nobody. Correctly fail-closed, but silently useless — and the failure surfaces on the peer's side as STATUS_UNKNOWN_RECIPIENT, the worst possible place to debug a local misconfiguration.

Fix: in the peering admin panel (Settings → Peering, #120's surface), when saving a peer whose receivers has groups but no users, and the instance has no IdP admin client: either refuse the save or warn plainly. Warning is probably right — the admin may be about to configure the client — but the text must say this list matches nobody until the admin client exists.

Small, self-contained, touches only the Settings panel JS and one server-side capability probe (whether spaces.Manager is configured is already known to cairnd at boot; the panel needs that bit exposed or inferred).

User-based lists are unaffected and work in every auth mode.

Split out of #105 so it survives that issue closing (the same near-miss as #104's notification gap). **The trap** (from #123): `CanReceive` takes groups as a parameter because the recipient is not authenticated — there is no session to read live groups from. The `cmd/cairnd` wiring passes `nil` when no IdP admin client is configured. So on such an instance, a **group-only** `receivers` allow-list matches nobody. Correctly fail-closed, but silently useless — and the failure surfaces on the *peer's* side as `STATUS_UNKNOWN_RECIPIENT`, the worst possible place to debug a local misconfiguration. **Fix**: in the peering admin panel (Settings → Peering, #120's surface), when saving a peer whose `receivers` has groups but no users, and the instance has no IdP admin client: either refuse the save or warn plainly. Warning is probably right — the admin may be about to configure the client — but the text must say *this list matches nobody until the admin client exists*. Small, self-contained, touches only the Settings panel JS and one server-side capability probe (whether `spaces.Manager` is configured is already known to `cairnd` at boot; the panel needs that bit exposed or inferred). User-based lists are unaffected and work in every auth mode.
Cordy closed this issue 2026-08-08 23:42:31 +00:00
Author
Owner

Shipped in v0.4.8 (PR #139), live on the dogfood.

The implementation turned out bigger than filed, because the receivers allowlist (#123) existed only in the registry: addPeer never decoded a receivers field, listPeers never returned it, the panel had no inputs for it — and peerRecipients passed nil groups unconditionally, so a group receivers list matched nobody on every instance, admin client or not. #129's warning alone would have been misleading; the whole path had to be completed.

Server:

  • addPeer decodes and stores receivers {users, groups}; listPeers returns each peer's receivers plus a top-level groupsLive capability bit — spacesMgr != nil, i.e. whether the Keycloak admin client (the same service-account client key custody uses) is configured. No new endpoint.
  • peerRecipients gains a groups hook wired to spaces.Manager.UserGroups when the admin client exists: inbound recipients now get real out-of-band group resolution, the completion #123 deferred. Without the client the hook is nil and group lists keep failing closed. Resolution errors degrade to nil (fail closed), never fail open.
  • New test TestAddPeerRoundTripsReceivers: round trip, groupsLive presence, a group receiver honoured when groups resolve, and the #129 trap itself — a group-only list matching nobody without resolvable groups.

Panel (Settings → Peering):

  • The register form now has two captioned sections — "May send to this peer" and "May receive from this peer" — each with Users/Groups fields, and a receivers hint mirroring the senders one: leave both empty and nobody here can receive; peering fails closed.
  • Saving a group-only receivers list while groupsLive is false shows exactly the warning this issue asked for: "Saved — but this receivers list matches nobody yet: group membership cannot be resolved without an IdP admin client. Add users, or configure the Keycloak admin client." Warn-not-refuse, as specified — the admin may be about to configure the client. i18n en/de/fr/it.
  • Peer rows show both directions at a glance: send: zeus321 · receive: staff (group).
  • Bonus fix: the peers list render read p.peers off an unparsed Response (same class as #136) — latent only because no peer had ever been registered.

Note for the dogfood: cairn-enc does have the Keycloak admin client configured (storage.encryption custody), so groupsLive is true there and group-based receiver lists genuinely resolve — the warning will only appear on instances without it.

Verified: gofmt/vet clean, full go test ./... green incl. the new test, node --check on both script blocks; image cordy/cairn:v0.4.8 (sha256:446d8bc6…) Running 1/1 on the dogfood with /data on the PVC.

Shipped in **v0.4.8** (PR #139), live on the dogfood. The implementation turned out bigger than filed, because the receivers allowlist (#123) existed **only in the registry**: `addPeer` never decoded a `receivers` field, `listPeers` never returned it, the panel had no inputs for it — and `peerRecipients` passed `nil` groups *unconditionally*, so a group receivers list matched nobody on every instance, admin client or not. #129's warning alone would have been misleading; the whole path had to be completed. **Server:** - `addPeer` decodes and stores `receivers {users, groups}`; `listPeers` returns each peer's receivers plus a top-level **`groupsLive`** capability bit — `spacesMgr != nil`, i.e. whether the Keycloak admin client (the same service-account client key custody uses) is configured. No new endpoint. - `peerRecipients` gains a `groups` hook wired to `spaces.Manager.UserGroups` when the admin client exists: inbound recipients now get real out-of-band group resolution, the completion #123 deferred. Without the client the hook is nil and group lists keep failing closed. Resolution errors degrade to nil (fail closed), never fail open. - New test `TestAddPeerRoundTripsReceivers`: round trip, `groupsLive` presence, a group receiver honoured when groups resolve, and the #129 trap itself — a group-only list matching nobody without resolvable groups. **Panel (Settings → Peering):** - The register form now has two captioned sections — **"May send to this peer"** and **"May receive from this peer"** — each with Users/Groups fields, and a receivers hint mirroring the senders one: leave both empty and nobody here can receive; peering fails closed. - Saving a **group-only** receivers list while `groupsLive` is false shows exactly the warning this issue asked for: *"Saved — but this receivers list matches nobody yet: group membership cannot be resolved without an IdP admin client. Add users, or configure the Keycloak admin client."* Warn-not-refuse, as specified — the admin may be about to configure the client. i18n en/de/fr/it. - Peer rows show both directions at a glance: `send: zeus321 · receive: staff (group)`. - Bonus fix: the peers list render read `p.peers` off an unparsed `Response` (same class as #136) — latent only because no peer had ever been registered. Note for the dogfood: `cairn-enc` **does** have the Keycloak admin client configured (`storage.encryption` custody), so `groupsLive` is true there and group-based receiver lists genuinely resolve — the warning will only appear on instances without it. Verified: gofmt/vet clean, full `go test ./...` green incl. the new test, `node --check` on both script blocks; image `cordy/cairn:v0.4.8` (`sha256:446d8bc6…`) Running 1/1 on the dogfood with `/data` on the PVC.
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#129
No description provided.