Skip to content

UN-3494 [GATED-FEAT] Email users and groups on access grant and revoke - #2224

Draft
kirtimanmishrazipstack wants to merge 3 commits into
mainfrom
UN-3494-group-sharing-notification
Draft

UN-3494 [GATED-FEAT] Email users and groups on access grant and revoke#2224
kirtimanmishrazipstack wants to merge 3 commits into
mainfrom
UN-3494-group-sharing-notification

Conversation

@kirtimanmishrazipstack

@kirtimanmishrazipstack kirtimanmishrazipstack commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

What

  • Emails every resource access change: granted or revoked, to a person or to a group's members — plus added to / removed from a group.
  • New internal APIs under /internal/v1/group-notification/ and two workers/notification tasks that call them.
  • Collapses the 7 per-viewset copies of the user notification hook into ResourceShareManagementMixin and drops the dead PATCH path.

Why

  • Sharing a resource granted access silently, revoking it told nobody, and group members had no way to know in either direction.
  • _notify_shared_users was still wired to partial_update, which no client has called since UN-2977, so even the direct-user share email had quietly stopped.

How

  • One hook in ResourceShareManagementMixin.share covers all 7 shareable resources plus cloud agentic; dispatch reuses resolve_transport (PG queue where pg_queue_enabled is on for the org, Celery otherwise).
  • Group revoke rides the existing resource-shared route with a share_action discriminator, mirroring membership-changed, defaulted at every hop so in-flight messages still run.
  • Fails closed behind Flipt group_sharing_notifications_enabled, and a revoke is suppressed when the user still reaches the resource via a group or shared_to_org.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • Low risk: notification-only side effects, all wrapped, gated on a default-off Flipt flag. The deletions are dead code — the partial_update hooks cannot fire since shared_users became ResourceMembership rows in UN-2202 Phase 2. Membership changes with no actor (org-removal cascade, Django admin, group deletion) deliberately do not notify.

Database Migrations

  • None

Env Config

  • Flipt group_sharing_notifications_enabled — new, gates the whole feature. Off or unreachable means no emails.
  • Flipt pg_queue_enabled — existing, reused to pick PG queue vs Celery transport.
  • New worker-pg-notification compose service (pg-queue profile), with optional overrides PG_NOTIFICATION_CONCURRENCY, PG_NOTIFICATION_VT_SECONDS, PG_NOTIFICATION_HEALTH_STALE_SECONDS.

Relevant Docs

Related Issues or PRs

Dependencies Versions

  • None

Notes on Testing

  • Verified manually against a dev org: grant, revoke, group grant, group revoke, co-owner add and co-owner remove all dispatch with the expected recipients and payloads, and a revoke is correctly suppressed while the user retains access through a group.

Screenshots

Checklist

I have read and understood the Contribution Guidelines.

…ship changes

Sharing a resource with a group gave its members access silently, and adding
or removing someone from a group told nobody. Both now send email.

- share_notifications.py holds the feature flag, the two task names and the two
  enqueue hooks. Dispatch uses the same resolve_transport branch the execution
  path uses: the PG queue where pg_queue_enabled is on for the org, Celery
  otherwise.
- One hook in ResourceShareManagementMixin.share covers all 7 resource types
  plus cloud agentic, including service-account shares — every group share
  funnels through it and shared_groups has no PATCH path. No on_commit needed:
  _commit's transaction has closed by the time the view resumes, so the diff
  reads committed state.
- Group membership hooks on the add and remove actions. The add serializer
  already subtracts existing members, so nobody is mailed twice.
- Internal endpoints under /internal/v1/group-notification/ do the work the
  worker cannot: group expansion, OrganizationMember re-validation (this is
  where the offboarding race closes), resource lookup via ShareableResource,
  and the kind -> ResourceType mapping, which is not 1:1 — pipelines split on
  pipeline_type and adapters four ways on adapter_type.
- Two worker tasks that only POST to that endpoint, since workers/ has no
  Django. They raise on failure, unlike _mark_buffer_outcome which has a reaper
  behind it, and retry transient 5xx in-task because a raise is terminal on the
  Celery transport.
- The whole feature is gated on Flipt group_sharing_notifications_enabled and
  fails closed: a blind Flipt, a missing org, or any dispatch error means no
  notification, never a broken share.
- worker-pg-notification compose service so the PG arm is not a black hole.

Membership changes with no actor (the org-removal cascade, Django admin, group
deletion) do not notify — SharingNotificationService requires an actor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b2f7f027-b86c-410a-998f-d3412bb5bfe0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

UN-2977 moved sharing from PATCH to POST /{id}/share/, but the mixin's
share action only diffed the groups axis. The per-viewset
_notify_shared_users hooks stayed on partial_update, which nothing calls
anymore, so sharing a resource with a user sent no email.

Snapshot every declared axis and invoke the hook after the commit; declare
it on the mixin as a no-op for hosts without a direct-share email.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kirtimanmishrazipstack kirtimanmishrazipstack changed the title UN-3494 [FEAT] Email group members on resource share and group member… UN-3494 [GATED-FEAT] Email group members on share and membership change Aug 4, 2026
…revoked

Sharing already emailed on grant; revoking told nobody. Both axes now notify,
and the seven duplicated copies of the user hook collapse into the share mixin.

- ResourceShareManagementMixin gains a concrete _notify_shared_users covering
  grant and revoke, driven by the OwnerManagementMixin seam every host already
  declares. The seven per-viewset overrides and their dead partial_update
  wrappers go with it — a host override would otherwise shadow the mixin and
  silently swallow the revoke mail.
- share() diffs both axes through _read_axis directly; AxisDiff,
  snapshot_share_axes, diff_share_axes and the share_axes ClassVar had no
  callers left.
- Group revoke rides the existing resource-shared route with a share_action
  discriminator, mirroring membership-changed — no new endpoint or worker task.
  Defaulted at every hop so in-flight messages still run.
- Suppressed when the user still reaches the resource via a group or
  shared_to_org: losing one axis is not losing access.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 4, 2026

Copy link
Copy Markdown

@kirtimanmishrazipstack kirtimanmishrazipstack changed the title UN-3494 [GATED-FEAT] Email group members on share and membership change UN-3494 [GATED-FEAT] Email users and groups on access grant and revoke Aug 4, 2026
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