Skip to content

fix(LaunchDarkly): Import processing not idempotent for completed requests#7954

Merged
khvn26 merged 2 commits into
Flagsmith:mainfrom
zain-asif-dev:fix/launch-darkly-import-empty-token-crash
Jul 8, 2026
Merged

fix(LaunchDarkly): Import processing not idempotent for completed requests#7954
khvn26 merged 2 commits into
Flagsmith:mainfrom
zain-asif-dev:fix/launch-darkly-import-empty-token-crash

Conversation

@zain-asif-dev

@zain-asif-dev zain-asif-dev commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
  • 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 #7950

The Sentry trace attached to the issue shows process_import_request crashing with:

django.core.signing.BadSignature: No ":" found in value

while unsigning import_request.ld_token. This isn't actually about the create endpoint accepting an empty token: CreateLaunchDarklyImportRequestSerializer.token is a plain CharField, and allow_blank defaults to False, so the create endpoint already rejects a blank token with a 400 (verified locally, see test plan below).

The real issue is in process_import_request itself: _complete_import_request clears import_request.ld_token to "" once the request finishes (success or failure), by design, so the token isn't kept around longer than needed. If process_import_request runs again for that same, already-completed request (for example a stale/duplicate task-processor delivery, which the task's timeout and failure-retry behavior make possible), it tries to unsign that now-blank token and blows up with the exact BadSignature error from the Sentry trace, rather than being a harmless no-op.

This adds a guard at the top of process_import_request that returns early (with a log message) if import_request.completed_at is already set, making reprocessing idempotent instead of crashing.

How did you test this code?

Added test_process_import_request__already_completed__does_not_reprocess, which marks an import request as completed with a blank ld_token (mirroring what _complete_import_request leaves behind) and asserts that calling process_import_request on it again is a no-op (the LaunchDarkly client is never re-instantiated). I confirmed this test reproduces the exact BadSignature: No ":" found in value crash from the Sentry trace when the guard is removed, and passes with the fix.

Also ran the full tests/unit/integrations/launch_darkly/ suite (47 passed), ruff check/ruff format --check, and mypy on the changed files.

…d requests

process_import_request() clears an import request's ld_token once it finishes (success or failure). If the task is delivered again for the same request (e.g. a stale/duplicate task-processor retry), it tried to unsign that now-empty token and crashed with django.core.signing.BadSignature: No ":" found in value, instead of being a harmless no-op. Guard against reprocessing an already-completed request.

Signed-off-by: Zain Asif <zainasif.jutt1@gmail.com>
@zain-asif-dev zain-asif-dev requested a review from a team as a code owner July 6, 2026 21:19
@zain-asif-dev zain-asif-dev requested review from khvn26 and removed request for a team July 6, 2026 21:19
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

@zain-asif-dev is attempting to deploy a commit to the Flagsmith Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

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: 9d976da5-046c-4fa0-8c11-338e9e96a4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 50986a6 and cfd0c07.

📒 Files selected for processing (2)
  • api/integrations/launch_darkly/services.py
  • api/tests/unit/integrations/launch_darkly/test_services.py
💤 Files with no reviewable changes (2)
  • api/integrations/launch_darkly/services.py
  • api/tests/unit/integrations/launch_darkly/test_services.py

📝 Walkthrough

Walkthrough

process_import_request now returns immediately when a LaunchDarklyImportRequest already has completed_at set, logging a warning instead of continuing. The test suite adds timezone-aware setup and a regression test that re-calls the function on an already completed request and checks that the LaunchDarkly client is not created and environments are not fetched.

Estimated code review effort: 2 (Simple) | ~10 minutes

Related PRs: None identified.

Suggested labels: bug, backend, tests

Suggested reviewers: None identified.

🐰 A guard now stands where imports once looped,
Completed requests are quietly scooped,
No token, no fetch, no client anew—
Just a warning logged, and the work is through.


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

@github-actions github-actions Bot added the api Issue related to the REST API label Jul 6, 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b6cfc865-b39a-4f55-8716-58da1e75f887

📥 Commits

Reviewing files that changed from the base of the PR and between da194ca and 50986a6.

📒 Files selected for processing (2)
  • api/integrations/launch_darkly/services.py
  • api/tests/unit/integrations/launch_darkly/test_services.py

Comment thread api/integrations/launch_darkly/services.py

@khvn26 khvn26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

just a couple edits away from merging this 👍

Comment thread api/integrations/launch_darkly/services.py Outdated
Comment thread api/tests/unit/integrations/launch_darkly/test_services.py Outdated
Comment thread api/tests/unit/integrations/launch_darkly/test_services.py Outdated
Signed-off-by: Zain Asif <zainasif.jutt1@gmail.com>
@zain-asif-dev

Copy link
Copy Markdown
Contributor Author

Removed those comments.

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.49%. Comparing base (da194ca) to head (cfd0c07).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7954      +/-   ##
==========================================
- Coverage   98.63%   98.49%   -0.15%     
==========================================
  Files        1497     1497              
  Lines       59189    59198       +9     
==========================================
- Hits        58383    58305      -78     
- Misses        806      893      +87     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@khvn26 khvn26 changed the title fix(api): make LaunchDarkly import processing idempotent for completed requests fix(LaunchDarkly): Import processing not idempotent for completed requests Jul 8, 2026
@khvn26 khvn26 merged commit 5cfb9f4 into Flagsmith:main Jul 8, 2026
23 of 26 checks passed
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LaunchDarkly import accepts empty LD token

2 participants