Skip to content

fix(ci): make multiprocessing rate-limit test picklable on Python 3.14#46

Merged
AlexanderWagnerDev merged 4 commits into
mainfrom
cursor/ci-autofix-automation-4266
Jul 11, 2026
Merged

fix(ci): make multiprocessing rate-limit test picklable on Python 3.14#46
AlexanderWagnerDev merged 4 commits into
mainfrom
cursor/ci-autofix-automation-4266

Conversation

@cursor

@cursor cursor Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Fixes CI failure on #45.

The test_login_rate_limit_is_per_process_with_memory_storage test failed in GitHub Actions with PicklingError because Python 3.14 uses forkserver-based multiprocessing, which cannot pickle nested functions passed to Process.

  • Move the worker target to module scope (_attempt_login_rate_limit_in_subprocess)
  • Add NOSONAR for intentional CSRF disable in the subprocess test helper
Open in Web View Automation 

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • Security

    • Login rate limiting is now shared across Gunicorn workers in the default Docker Compose deployment, preventing per-worker bypasses.
    • Added Redis-backed rate-limit storage to the standard setup.
  • Configuration

    • Introduced optional RATELIMIT_STORAGE_URI to control where rate-limit state is stored (e.g., Redis for multi-worker, memory for local).
  • Documentation

    • Updated CHANGELOG.md, README.md, and .env.example with the new configuration details.
  • Tests

    • Added multiprocessing-based coverage to verify rate limiting behavior across requests and independent workers.

cursoragent and others added 2 commits July 11, 2026 02:02
Default docker-compose stack now runs Redis and sets
RATELIMIT_STORAGE_URI=redis://redis:6379/0 so the 5/min login cap is
enforced globally instead of per worker (fixes #44).

Adds regression tests documenting single-process enforcement and the
per-process memory:// behavior that multi-worker deployments must avoid.

Co-authored-by: Alexander Wagner <info@alexanderwagnerdev.com>
Move attempt_logins to module scope so Process can pickle the target on
forkserver-based multiprocessing (Python 3.14 CI). Add NOSONAR for
intentional CSRF disable in the subprocess test helper.

Co-authored-by: Alexander Wagner <info@alexanderwagnerdev.com>
@coderabbitai

coderabbitai Bot commented Jul 11, 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: CHILL

Plan: Pro Plus

Run ID: 732da949-0f40-42f3-adb7-b4f579fe7003

📥 Commits

Reviewing files that changed from the base of the PR and between 2860249 and 4b19d6b.

📒 Files selected for processing (2)
  • .env.example
  • tests/test_login_routes.py
✅ Files skipped from review due to trivial changes (1)
  • .env.example
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_login_routes.py

📝 Walkthrough

Walkthrough

The change documents configurable rate-limit storage, provisions Redis in Docker Compose for shared Gunicorn-worker limits, and tests login throttling plus per-process behavior with in-memory storage.

Changes

Login rate-limit storage

Layer / File(s) Summary
Rate-limit storage configuration
.env.example, README.md, CHANGELOG.md
Documents RATELIMIT_STORAGE_URI, its in-memory development setting, and the Redis-backed Docker Compose default.
Docker Compose Redis wiring
docker-compose.yml
Adds a health-checked Redis service and configures openrtmp-panel to use it after Redis is healthy.
Login rate-limit validation
tests/test_login_routes.py
Tests five accepted failed-login attempts followed by HTTP 429, and verifies that memory:// limits are isolated per subprocess.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main CI fix: making the multiprocessing rate-limit test picklable on Python 3.14.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/ci-autofix-automation-4266

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

SonarCloud flagged the new WTF_CSRF_ENABLED=False line in
test_login_rate_limit_blocks_after_five_attempts as an unreviewed
Security Hotspot (S4502), dropping the PR's Security Rating to D.
Mark it with the same NOSONAR justification already used for the
equivalent line in the subprocess helper.
@AlexanderWagnerDev AlexanderWagnerDev marked this pull request as ready for review July 11, 2026 08:45

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.env.example:
- Around line 26-28: Update the RATELIMIT_STORAGE_URI example so copying
.env.example preserves Compose’s Redis-backed rate-limit configuration: leave
the key unset/commented, or set it to the Redis URI. If using the Redis value,
document the memory:// override for single-process local development in the
surrounding environment guidance.

In `@tests/test_login_routes.py`:
- Around line 56-63: Set RATELIMIT_STORAGE_URI to the intended memory:// backend
before each create_app() call, including the subprocess helper
_attempt_login_rate_limit_in_subprocess and the other application setup at the
referenced location. Ensure the environment override occurs before application
initialization so externally configured Redis values cannot affect these
isolation tests.
- Around line 108-114: Update the multiprocessing test around the worker
start/join and queue collection to use finite timeouts for both worker.join()
and queue.get(), so crashed or stalled children fail promptly instead of hanging
CI. After each join, inspect the worker’s exit code and fail the test when it is
nonzero, while preserving the existing accepted_per_worker assertion for
successful workers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 49d83180-6244-4a20-a17a-f4e30924cd7e

📥 Commits

Reviewing files that changed from the base of the PR and between c5cc8d9 and 2860249.

📒 Files selected for processing (5)
  • .env.example
  • CHANGELOG.md
  • README.md
  • docker-compose.yml
  • tests/test_login_routes.py

Comment thread .env.example Outdated
Comment thread tests/test_login_routes.py
Comment thread tests/test_login_routes.py

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2860249036

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .env.example Outdated
SECRET_KEY=<generate-with-python3-secrets-token-hex-32>
# Shared rate-limit store for multi-worker Gunicorn (docker-compose defaults to redis://redis:6379/0).
# Use memory:// only for single-process local dev (python3 app.py).
RATELIMIT_STORAGE_URI=memory://

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't override Redis from the example env

When a user follows the README quick start and copies .env.example to .env, Compose uses that .env value for interpolation, and ${RATELIMIT_STORAGE_URI:-redis://redis:6379/0} in docker-compose.yml only falls back to Redis when the variable is unset or empty. Because this new line sets a non-empty memory://, the Docker stack will start Redis but configure the panel to use per-process memory limits, so multi-worker deployments still allow 5 × worker_count login attempts per minute; leave this unset/commented or set it to redis://redis:6379/0 in the example.

Useful? React with 👍 / 👎.

Comment thread tests/test_login_routes.py Outdated
Comment on lines +110 to +113
for worker in workers:
worker.join()

accepted_per_worker = [queue.get() for _ in workers]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fail instead of blocking on worker failures

If any child process exits before queue.put(...) (for example because app initialization fails under a CI environment variable or the forkserver import path regresses), the parent joins it and then blocks forever waiting for a result that will never arrive. Checking each worker.exitcode and/or using bounded join/queue.get(timeout=...) would turn those subprocess failures into actionable test failures instead of CI timeouts.

Useful? React with 👍 / 👎.

- .env.example: stop shipping RATELIMIT_STORAGE_URI=memory:// as a
  concrete value. Since docker-compose's ${VAR:-redis://...} fallback
  only triggers when the var is unset/empty, copying .env.example to
  .env per the README quick start silently re-enabled per-worker
  memory limiting and reopened the brute-force gap from #44. Leave it
  commented out with the memory:// override documented for local dev.
- tests: pin RATELIMIT_STORAGE_URI to memory:// via
  patch("app.Config.RATELIMIT_STORAGE_URI", ...) before create_app()
  in both rate-limit tests so they stay hermetic regardless of the
  ambient environment.
- tests: bound the multiprocessing isolation test's worker.join() and
  queue.get() with timeouts and check exit codes, so a crashed child
  fails the test instead of hanging CI indefinitely.
@sonarqubecloud

Copy link
Copy Markdown

@AlexanderWagnerDev AlexanderWagnerDev merged commit e30f0b6 into main Jul 11, 2026
11 checks passed
@AlexanderWagnerDev AlexanderWagnerDev deleted the cursor/ci-autofix-automation-4266 branch July 11, 2026 09:31
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.

3 participants