feat(webhooks): allow org members read-only access to org webhooks#1043
Merged
Conversation
Org members previously had no visibility into webhooks owned by the
organization, leaving them unable to spot delivery failures and notify
admins. Add a read-only path: list_webhooks and get_webhook fall through
to is_org_member when no direct or own-resource permission applies.
Mutating handlers (create/update/delete/rotate-secret) keep the existing
can_manage_org_resource check, so writes still require owner/admin.
Frontend: NotificationSettings gains a readOnly prop that hides email
and low-balance toggles, the Add Webhook button, and the per-row
Switch/Edit/Delete controls. MyOrganization now always renders the
panel and passes readOnly={!canManage}, so members see the same webhook
list (URL, events, scope, enabled state, auto-disable warning) without
any controls or secrets.
Deploying control-layer with
|
| Latest commit: |
513833d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6838df98.control-layer.pages.dev |
| Branch Preview URL: | https://feat-webhooks-readonly-org-m.control-layer.pages.dev |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends webhook visibility so non-admin organization members can read (list/get) their organization’s webhooks in both the API and dashboard, while keeping all webhook mutations restricted to org owners/admins.
Changes:
- Backend:
list_webhooks/get_webhooknow fall back topermissions::is_org_member(...)when the caller lacksReadAll/ReadOwn. - Backend: adds integration tests covering org-member read access, outsider denial, and mutation denial/regression.
- Frontend: adds a
readOnlyrendering mode toNotificationSettingsand always renders it inMyOrganization(members see a read-only “Webhooks” view).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
dwctl/src/api/handlers/webhooks.rs |
Relaxes read authorization for org-owned webhooks to any org member; adds integration tests for the new access rules. |
dashboard/src/components/features/organizations/MyOrganization.tsx |
Always renders NotificationSettings, passing readOnly for non-admin members. |
dashboard/src/components/features/organizations/MyOrganization.test.tsx |
Updates member-role test expectations for the new read-only webhooks UI. |
dashboard/src/components/features/notifications/NotificationSettings.tsx |
Adds readOnly mode to hide notification toggles and webhook mutation controls while still showing the webhook list. |
Comments suppressed due to low confidence (1)
dashboard/src/components/features/notifications/NotificationSettings.tsx:173
- In
readOnlymode this component still executesuseUser(userId), but none of the fetcheduserfields are rendered/used (email/low-balance controls are hidden and no mutations can be triggered). This adds an unnecessary request for regular org members and could also surface avoidable 403s if user-read rules change. Consider adding anenabledoption touseUser(similar touseUsers) and disabling the query whenreadOnlyis true, or splitting the webhook-only view into a smaller component.
export const NotificationSettings: React.FC<NotificationSettingsProps> = ({
userId,
showPlatformScope = false,
isOrganization = false,
readOnly = false,
}) => {
const { data: user, refetch: refetchUser } = useUser(userId);
const updateUserMutation = useUpdateUser();
const updateOrgMutation = useUpdateOrganization();
const navigate = useNavigate();
const { data: webhooks } = useWebhooks(userId);
const createWebhookMutation = useCreateWebhook();
Comment on lines
+57
to
+67
| .await | ||
| .map_err(Error::Database)?; | ||
| if !can_org { | ||
| if !is_member { |
Comment on lines
+254
to
+264
| .await | ||
| .map_err(Error::Database)?; | ||
| if !can_org { | ||
| if !is_member { |
- Update OpenAPI descriptions on list_webhooks and get_webhook to mention
org-member read access, so API consumers aren't misled by stale docs.
- Inline comments now explain the three-tier authorization (admin / own /
org member) so the rule is documented next to the check.
- Skip the useUser fetch in NotificationSettings when readOnly: every
consumer of the user object lives inside the email/low-balance section,
which read-only callers don't render. Adds an `enabled` option to
useUser, mirroring the existing useUsers pattern, so a member viewing
the org's webhooks doesn't fire a needless GET /users/{org_id}.
Contributor
Author
|
/build-staging |
|
Staging image |
sejori
pushed a commit
that referenced
this pull request
May 5, 2026
🤖 I have created a release *beep* *boop* --- ## [8.46.0](v8.45.0...v8.46.0) (2026-05-05) ### Features * **webhooks:** allow org members read-only access to org webhooks ([#1043](#1043)) ([4bf5b54](4bf5b54)) ### Bug Fixes * **deps:** clear all 36 open Dependabot vulnerabilities ([#1045](#1045)) ([fa79316](fa79316)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
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.
Summary
Currently, only owner/admin members of an org can see the org's webhooks. Plain members have no way to spot when a webhook has been auto-disabled by the circuit breaker or when deliveries are failing — they can't notify an admin without first noticing something has gone wrong.
This PR adds a read-only path:
dwctl/src/api/handlers/webhooks.rs):list_webhooksandget_webhookfall through tois_org_memberwhen the caller has no direct/own permission. Org-scoped webhooks live atuser_id = org_id, so this lets any member of that org user read the list. Mutating handlers (create,update,delete,rotate_secret) keep the existingcan_manage_org_resourcecheck, so writes still require owner/admin.NotificationSettings): newreadOnlyprop hides email + low-balance toggles, the Add Webhook button, and the per-row Switch/Edit/Delete controls. Renders the same webhook list — URL, description, scope, event types, enabled state, auto-disable warning — without any controls.MyOrganization): always rendersNotificationSettings, passesreadOnly={!canManage}. Owners/admins see no change; plain members now see a read-only "Webhooks" card.Out of scope (intentional)
user_id, and the dashboard only ever requestsuser_id = active_organization_id, members never see platform-scope webhooks through this path.is_org_membercheck is keyed on the org user being requested, so a member of org A cannot enumerate org B's webhooks.WebhookResponsetype omits thesecretfield; onlycreateandrotate-secretever returnWebhookWithSecretResponse, and both remain admin-only.Test plan
Backend (8 new integration tests in
dwctl/src/api/handlers/webhooks.rs):test_org_member_can_list_org_webhooks_without_secrets— member lists the org's webhooks; raw JSON has nosecretfieldtest_org_member_can_get_single_org_webhook— single-webhook GET also works and omits secrettest_non_member_cannot_list_org_webhooks— outsider gets 403test_org_member_cannot_create_org_webhook— POST → 403test_org_member_cannot_update_org_webhook— PATCH → 403test_org_member_cannot_delete_org_webhook— DELETE → 403test_org_member_cannot_rotate_org_webhook_secret— POST/rotate-secret→ 403test_org_admin_can_still_manage_webhooks— regression guard for the existing owner/admin write pathFrontend:
MyOrganization.test.tsx— updated the "regular member" case to assert the "Webhooks" heading is present and admin-only controls (Add webhook, Email notifications switch) are absent. Owner/admin tests unchanged and still pass.tsc -b --noEmitandeslint --max-warnings 0clean.