Skip to content

fix(segments): Segment Change Requests bypassable via segment deletion - #8358

Merged
khvn26 merged 11 commits into
mainfrom
fix/segment-change-request-bypass
Aug 26, 2026
Merged

fix(segments): Segment Change Requests bypassable via segment deletion#8358
khvn26 merged 11 commits into
mainfrom
fix/segment-change-request-bypass

Conversation

@khvn26

@khvn26 khvn26 commented Aug 25, 2026

Copy link
Copy Markdown
Member

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Closes #7532.

In this PR, we prevent the following when Segment Change Requests are enabled:

  • Deleting a segment that has live or scheduled feature overrides. Overrides that exist only inside an uncommitted change request do not count.
  • Editing a segment directly. PUT and PATCH on a segment are refused, including metadata-only writes. Drafts held by a change request are exempt, since editing those is the workflow rather than a way around it.

Supporting changes:

  • ChangeRequestsEnabledError moves from features/future/exceptions.py to core/exceptions.py so both features and segments raise the same 409 and error code. Its detail message is now generic.
  • Project.is_workflow_enabled, mirroring Environment.is_workflow_enabled.
  • EnvironmentFeatureVersionManager.get_superseded_versions(), which answers "has a later version already replaced this one" as a correlated subquery. Ordering by go-live rather than creation is deliberate, per Enabled features can disagree with the flags actually served after a scheduled change #8127.
  • Segments now expose has_overrides, so the UI is able to gray out submission buttons based on it.
  • segments/views.py moves to structlog, emitting segments.update_rejected and segments.delete_rejected.

Deliberately out of scope:

  • Segment creation stays ungated. A segment serves nothing until an override points at it, and adding overrides is governed by Feature Change Requests.
  • Custom fields (metadata) are carried into a segment change request but never shown to the approver and dropped on commit (Segment change requests silently discard custom field edits #8350). Because this PR gates metadata-only writes too, custom fields cannot be changed on a change-request-enabled project until Segment change requests silently discard custom field edits #8350 is fixed.
  • Override writes themselves are only gated on the newer flag endpoints. FeatureSegmentViewSet and EnvironmentFeatureVersionViewSet.create/publish have no change request check, so the API route around Feature Change Requests remains open. The documentation added here is careful not to claim otherwise.

How did you test this code?

Added unit tests, and benchmarked EnvironmentFeatureVersionManager.get_superseded_versions().

@khvn26
khvn26 requested review from a team as code owners August 25, 2026 12:19
@khvn26
khvn26 requested review from adamvialpando and matthewelwell and removed request for a team August 25, 2026 12:19
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Aug 26, 2026 12:00pm
flagsmith-frontend-preview Ignored Ignored Preview Aug 26, 2026 12:00pm
flagsmith-frontend-staging Ignored Ignored Preview Aug 26, 2026 12:00pm

Request Review

@github-actions github-actions Bot added api Issue related to the REST API docs Documentation updates labels Aug 25, 2026
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 91c5bc4e-2824-407c-8d5a-05830b764e84

📥 Commits

Reviewing files that changed from the base of the PR and between fb45137 and 04edee6.

📒 Files selected for processing (4)
  • api/features/versioning/managers.py
  • api/segments/services.py
  • api/segments/views.py
  • api/tests/unit/segments/test_unit_segments_views.py
💤 Files with no reviewable changes (2)
  • api/tests/unit/segments/test_unit_segments_views.py
  • api/segments/views.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change centralises ChangeRequestsEnabledError and adds project workflow detection. It calculates effective segment overrides across legacy and v2 versioning. Segment updates and deletions return HTTP 409 when workflow rules block the operation. Segment responses expose the read-only has_overrides field. Tests, documentation, observability events, and OpenAPI schemas cover the new behaviour.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟠 High · up to 04ede

The change is intended to prevent direct segment edits and deletion from bypassing change-request approval, but current implementation risks still allowing protected segments to be deleted—especially for versioned segments or during concurrent override changes—and the rejection test may not verify the required response. These issues should be addressed before merge.


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.

@khvn26
khvn26 force-pushed the fix/segment-change-request-bypass branch from 7a3b5a9 to fb022d1 Compare August 25, 2026 12:49
@github-actions github-actions Bot removed the docs Documentation updates label Aug 25, 2026
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-8358 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api-test:pr-8358 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-8358 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api:pr-8358 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8358 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8358 Finished ✅ Results

@github-actions github-actions Bot added the fix label Aug 25, 2026
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor
✅ private-cloud · depot-ubuntu-latest-16 — run #19839 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  3 passed

Details

stats  3 tests across 3 suites
duration  35.9 seconds
commit  f3b12dc
info  🔄 Run: #19839 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19839 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  3 passed

Details

stats  3 tests across 3 suites
duration  38.8 seconds
commit  f3b12dc
info  🔄 Run: #19839 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19840 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  45.4 seconds
commit  0704823
info  🔄 Run: #19840 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19839 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  38.1 seconds
commit  f3b12dc
info  🔄 Run: #19839 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19839 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  46.5 seconds
commit  f3b12dc
info  🔄 Run: #19839 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19840 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  36.6 seconds
commit  0704823
info  🔄 Run: #19840 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19835 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  35 seconds
commit  ff9106a
info  🔄 Run: #19835 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19837 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  50.2 seconds
commit  2cba6de
info  🔄 Run: #19837 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19835 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  37 seconds
commit  ff9106a
info  🔄 Run: #19835 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19837 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41 seconds
commit  2cba6de
info  🔄 Run: #19837 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19835 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41.8 seconds
commit  ff9106a
info  🔄 Run: #19835 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19831 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  3 passed

Details

stats  3 tests across 3 suites
duration  37.4 seconds
commit  04edee6
info  🔄 Run: #19831 (attempt 1)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2f7bc5d1-6781-4961-bd6c-07616b1340b0

📥 Commits

Reviewing files that changed from the base of the PR and between 7a3b5a9 and 89441b6.

📒 Files selected for processing (6)
  • api/segments/serializers.py
  • api/segments/views.py
  • api/tests/unit/segments/test_unit_segments_views.py
  • docs/docs/deployment-self-hosting/observability/_events-catalogue.md
  • mcp/src/flagsmith_mcp/openapi.json
  • openapi.yaml

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.

Comment thread api/tests/unit/segments/test_unit_segments_views.py Outdated
@github-actions github-actions Bot removed fix docs Documentation updates labels Aug 25, 2026
@github-actions github-actions Bot added the fix label Aug 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
api/segments/views.py (2)

105-111: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep override detection aligned with delete_segment().

FeatureSegment.segment accepts any Segment, and override creation stores the supplied segment ID. If an effective override targets a versioned segment, the view checks only the canonical segment ID, while delete_segment() removes overrides for the canonical segment and its versions. The view can therefore allow deletion without raising ChangeRequestsEnabledError. Share the expanded segment-ID set, or perform the check inside delete_segment().


286-288: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make the override check and deletion atomic.

When change requests are enabled, an override can be committed after _check_segment_is_deletable() and before delete_segment() starts its transaction. delete_segment() then removes the override without rejecting the deletion. Re-check within the deletion transaction and share serialisation with override writers. Add a concurrent test.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 09597a5a-6ad4-445c-9bec-57ac572dfcfc

📥 Commits

Reviewing files that changed from the base of the PR and between 366eeb2 and fb45137.

📒 Files selected for processing (1)
  • api/segments/views.py

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.

@matthewelwell matthewelwell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM - one minor comment on function naming.

Comment thread api/features/versioning/managers.py Outdated
@github-actions github-actions Bot added docs Documentation updates fix and removed fix docs Documentation updates labels Aug 26, 2026
@github-actions github-actions Bot added fix and removed fix docs Documentation updates labels Aug 26, 2026
Comment thread api/features/versioning/managers.py Outdated
khvn26 and others added 2 commits August 26, 2026 12:59
Co-authored-by: Matthew Elwell <matthew.elwell@flagsmith.com>
@github-actions github-actions Bot added fix and removed fix docs Documentation updates labels Aug 26, 2026
@khvn26
khvn26 requested a review from matthewelwell August 26, 2026 12:00
@khvn26
khvn26 merged commit 56b6579 into main Aug 26, 2026
42 checks passed
@khvn26
khvn26 deleted the fix/segment-change-request-bypass branch August 26, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Segment Change Requests bypassable via segment create or delete

3 participants