Skip to content

fix(team): stop reading a role restriction as a revoked team vault (#187) - #191

Merged
kipavy merged 1 commit into
devfrom
fix/connect-only-team-vault-187
Aug 26, 2026
Merged

fix(team): stop reading a role restriction as a revoked team vault (#187)#191
kipavy merged 1 commit into
devfrom
fix/connect-only-team-vault-187

Conversation

@kipavy

@kipavy kipavy commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Closes #187. Also answers the "what a connect-only invitee should see first" half of #70.

The bug

A member holding only the built-in connect-only role opens the team vault they were just invited to and sees "Access revoked — You no longer have access to this team vault." They were never revoked.

connect-only is 28676 = CONNECT | START_TERMINAL_SESSION | JOIN_TERMINAL_SESSION | VIEW_TERMINAL_SESSIONS. No VIEW_SECRETS, so GET /v1/teams/:team_id/vault-key returns 403 and getTeamVaultKey maps 403 to "forbidden" — the revocation state.

It bites at exactly one moment. fetchTeamData tries listTeamObjects first; that route is membership-gated and returns plaintext metadata, so once the vault holds anything it opens for a connect-only member without the key ever being needed. It is the empty vault — the one a joiner meets right after the owner converts a private vault — that falls through to the key route and 403s.

The fix

The route cannot separate "removed from the team" from "your role lacks VIEW_SECRETS" — both are 403. The client can: the server drops revoked teams from the caller's team list, and onTeamRemoved clears the store. So a 403 while the team is still listed is a role restriction.

Such a member reads this vault through the object routes only, which means the empty list they just got is their view of the vault. Show it, rather than a false revocation.

Genuine revocation is unaffected — it arrives through onTeamRemoved and through a 403 on list_objects itself (membership-gated), both of which still land on forbidden.

What this deliberately does not do

It does not widen get_my_vault_key to PERM_CONNECT || PERM_VIEW_SECRETS, the "Yes" option in #187. That buys nothing for hosts — they never needed the key — and it is unsafe until VoltiusApp/server#11 lands, because GET /sync-blob is membership-only today and the pair would hand a connect-only member the whole vault in plaintext.

It also does not fix the deeper problem the investigation turned up: a connect-only member can never fetch any credential ciphertext (list_secrets requires VIEW_SECRETS) nor the key to decrypt it, so the role cannot connect to any host with a stored password or key passphrase. Filed as #190 — it needs a design decision about what PERM_CONNECT means.

Tests

Two new tests in teamVaultSync.data.test.ts: a 403 on the key route resolves to an empty loaded vault when the team is still listed, and still resolves to forbidden when it is not. Verified against a negative baseline — the first test fails on dev.

npx tsc --noEmit → clean
vitest run → 186 files, 1505 tests, 0 failures

Server side: VoltiusApp/server#11

)

A connect-only member holds no VIEW_SECRETS, so GET /vault-key 403s for
them. On an empty team vault — the one a joiner meets right after the
owner converts a private vault — fetchTeamData falls through to that
route and rendered the 403 as "Access revoked". They were never revoked.

The route cannot separate "removed from the team" from "your role lacks
VIEW_SECRETS", but the client can: a revoked member no longer has the
team in their own team list. A 403 while the team is still listed is a
role restriction, and such a member reads the vault through the object
routes only — so the empty list they just got IS their view of it.

Answers the "what a connect-only invitee should see first" half of #70:
the vault, empty, like any other empty vault.
@kipavy
kipavy merged commit c00143a into dev Aug 26, 2026
4 checks passed
@kipavy
kipavy deleted the fix/connect-only-team-vault-187 branch August 26, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant