feat(slack): require full slack membership and expose it via oidc - #121
Open
jaspermayone with Copilot wants to merge 3 commits into
Open
jaspermayone with Copilot wants to merge 3 commits into
jaspermayone with Copilot wants to merge 3 commits into
Conversation
Copilot
AI
changed the title
[WIP] Fix membership validation for Slack invites in Weave
WIP: enforce Slack-backed membership state in OIDC (session interrupted)
Sep 28, 2026
4 of 5 tasks
jaspermayone
marked this pull request as ready for review
September 28, 2026 21:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A Weave account does not make someone a full member of the Patchwork Labs Slack. Downstream apps (Krater) assumed that it does. This PR makes full Slack membership an explicit state, gives people one page that takes them through joining, and exposes the state to OAuth clients.
Fixes #118
Membership state
users.slack_membership:pending(default) ormember.memberwhen Slack reports a regular (non-guest, non-deactivated) account:SlackCodeOfConductAcceptedJobsets it afterusers.admin.setRegularsucceeds.team_joinanduser_changewebhooks set it from the Slack user flags.user_changealso ends membership when an account is made a guest or deactivated.SyncUserToSlackJobset it fromusers.list/users.lookupByEmail.slack_idwho were not invited as guests by Weave, or who accepted the CoC, start asmember. The next Slack sync corrects any wrong guess.User#slack_member?now means full membership. The old meaning (has aslack_id) isUser#in_slack_workspace?.stateDiagram-v2 [*] --> pending: sign up pending --> pending: confirm email, Slack invite sent pending --> pending: accept invite (single-channel guest) pending --> member: accept Code of Conduct (promoted) member --> pending: made a guest or deactivated in Slack [*] --> member: imported from Slack as a full memberOnboarding:
slack.patchworklabs.org→/slackslack.*redirects (302) to/slackon the canonical host, so the session cookie applies./slackshows the next step: sign up, send invite, accept invite, accept Code of Conduct, member.POST /slacksends or resends the invite (10 minute cooldown, plus a Rack::Attack throttle).POST /slack/code-of-conductaccepts the CoC from the web, for people who can't find the Slack DM. It also retries a failed promotion./sends signed-in pending users to/slack. The profile page shows a "Finish joining" banner. The home page links to "Join the Slack".OIDC
New optional scope
slackwith two claims, in the id_token and at/oauth/userinfo:slack_membertrueonly for full (non-guest) membersslack_idPending users can still sign in. Each client decides what to allow. Krater must add
slackto its registered scopes and request it.UserSerializeralso includes both fields.Deploy steps (outside this repo)
slack.patchworklabs.orgin Cloudflare (proxied, same asweave).hosts/alastor/configuration.nix,idprouter): add|| Host(\slack.patchworklabs.org`)` to the rule.Tests
bundle exec rspec: 446 examples, 0 failures.bin/rails test: 11 runs, 0 failures. RuboCop, Brakeman, herb, zeitwerk: clean.