fix(api): tighten published mutation scopes#113120
fix(api): tighten published mutation scopes#113120dcramer wants to merge 11 commits intodcramer/fix/api-readonly-mutation-notesfrom
Conversation
Tighten published mutation endpoints that already have an obvious existing write-capable scope. Previously, several write methods accepted readonly scopes like org:read, project:read, or event:read even though they mutate server-side state. Require the existing write scope for those surfaces instead. Keep session behavior intact, including team-scoped alert access, but stop exposing readonly token writes through these endpoints. Co-Authored-By: OpenAI Codex <noreply@openai.com>
This comment was marked as low quality.
This comment was marked as low quality.
Drop the member-session surfaces that were not actually uncontroversial from this PR. Dashboards, code mappings, repo path parsing, key transactions, and org auth token updates still rely on broader session behavior today, so tightening them here broke existing member flows. Revert those paths in this branch and keep the safe mutation tightening for incidents, alerts, user issue creation, data export, and replay summary. Also keep replay delete in the project scope domain so delete remains consistent with the rest of the replay permission class. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Add an explicit owner for static/app/components/markdownTextArea.tsx so the branch clears the CODEOWNERS coverage check. The file was missing ownership coverage entirely, which caused the fresh PR run to fail even though the API changes on this branch are backend-only. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Keep the replay permission maps aligned with the current repo style of listing implied scopes explicitly. This does not change the effective permissions on these endpoints, but it removes a local inconsistency in this PR where replay endpoints relied on hierarchy expansion while nearby scope maps did not. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Backend Test FailuresFailures on
|
Replay delete is a public mutation, so it should not depend on a project read-style contract. Move the DELETE permission to event write/admin so member sessions keep working while token auth requires a real write scope. Add direct endpoint tests covering the token contract: event:read is denied and event:write is allowed for replay delete. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Remove the incident permission change from the existing-write-scope pass. Incident mutation has an older member-access contract tied to project access, so tightening it cleanly needs a dedicated scope decision instead of being folded into the uncontroversial cleanup. Also drop an unrelated CODEOWNERS hunk so this branch stays focused on backend mutation scope changes. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Keep replay summary POST on read-level replay scopes and mark it as an explicit readonly-mutation exception, since it derives summary data from existing replay/event data. Document the preview endpoints that intentionally keep write-aligned permissions because they are part of alert and monitor authoring flows, even though they use POST helper endpoints. Add replay summary token tests covering the read-scope contract. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Add endpoint-level regression tests for the scope changes on this branch so each permission update is covered directly. Cover the write-scope transitions for data export, alert rule creation, project user issues, replay delete, detector updates, and the alert helper endpoints. This keeps the branch from relying on indirect role coverage alone and makes the replay summary readonly exception explicit next to direct token tests. Refs getsentry/getsentry#19897 Co-Authored-By: OpenAI Codex <noreply@openai.com>
Backend Test FailuresFailures on
|
Use supported token auth for data export, give alert-rule token tests a valid member project setup, and return a real anomaly payload in the Seer regression test. These tests were asserting the new permission contracts, but two of them were exercising invalid success paths and one was using an auth shape that the endpoint does not serialize correctly. Co-Authored-By: Codex <noreply@openai.com>
Backend Test FailuresFailures on
|
Alert and monitor mutations now accept alerts:write at the endpoint level, but the nested project validators still required project:read. That let the request through permission checks and then failed token-based create and update flows with a 400 during validation. Allow those serializers to validate project selection against the same write-capable scopes the endpoints already advertise, and add direct token regression tests for alert rule updates and monitor creation so the contract stays enforced. Co-Authored-By: OpenAI Codex <noreply@openai.com>
Limit org-scoped alert and detector mutations to either the target project's alerts:write access or an explicit endpoint opt-in for the older team-scoped fallback. This closes the cross-team mutation path on alert rule and detector details, and adds project-scoped checks for the other shared consumers that still relied on the broad organization permission. Align replay deletion with the rest of the event delete surface by requiring event:admin instead of event:write. Add regression coverage for the scope changes and the cross-project authorization cases. Co-Authored-By: Codex <noreply@openai.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2a711cc. Configure here.
| request.access.has_any_project_scope(monitor.project, ALERT_MUTATION_SCOPES) | ||
| for monitor in monitors | ||
| ): | ||
| return self.respond(status=403) |
There was a problem hiding this comment.
monitor.project attribute does not exist on Monitor model
High Severity
The Monitor model defines project_id as a BoundedBigIntegerField, not a ForeignKey. This means monitor.project does not exist as an attribute—accessing it will raise an AttributeError at runtime, causing a 500 error on every bulk-edit PUT request to this endpoint. The check needs to look up the Project by monitor.project_id first, or use select_related with a proper FK relationship.
Reviewed by Cursor Bugbot for commit 2a711cc. Configure here.
Backend Test FailuresFailures on
|


Tighten published mutation endpoints so token scopes match the API contract.
This PR removes readonly token access from a set of uncontroversial published mutation paths and aligns the affected alert and replay helpers with the permission model they already conceptually belong to. It stays within the existing scope model and does not introduce new scopes.
The direct permission changes in this PR are:
OrganizationDataExportPermission.POSTnow requiresevent:write/event:admin.ProjectUserIssuePermission.POSTnow requiresevent:write/event:admin.ReplayDetailsPermission.DELETEnow requiresevent:admin, matching the rest of the event and issue delete surface.OrganizationAlertRulePermissionmutation paths now require alert-write access for the actual target project instead of being satisfied by alert-write access on any team in the organization.OrganizationDetectorPermissionmutation paths follow the same target-project rule.This PR also aligns nested validation with those endpoint permissions:
A few POST helpers are intentionally still non-persistent helper endpoints, but their permission model is now explicit and covered by tests:
The goal is straightforward: for public API tokens, readonly scopes should not be enough to hit write endpoints, and team-scoped alert access should only authorize mutations for the projects that access actually covers.
Every changed endpoint in this PR has direct regression coverage for the relevant allow and deny behavior.
Refs getsentry/getsentry#19897