Close test gaps and harden link consumption - #5
Open
lukeburden wants to merge 2 commits into
Open
Conversation
Tests (38 -> 52): - Assert the Location header returned by the create API, including with a custom AUTHLINK_URL_TEMPLATE - Cover X-Forwarded-For IP extraction: public XFF, leftmost-private chain failing closed outside DEBUG, and wholly-private XFF falling back to REMOTE_ADDR (pins the ipware 7 semantics shipped in 2.0.0) - Assert the whitelist middleware ignores password-established sessions - Assert AuthLinkBackend.authenticate() never authenticates anyone - Cover unknown-key 404 and AUTHLINK_NON_SUCCESS_REDIRECT_URL - Cover generate_authlink_key length/charset and AUTHLINK_KEY_LENGTH - Add an end-to-end test: API create -> consume in a fresh session -> whitelisted URL accessible, everything else 403 Fixes: - Lock the AuthLink row (select_for_update) during consumption so concurrent requests cannot both pass the is_used check - Document AUTHLINK_NON_SUCCESS_REDIRECT_URL and AUTHLINK_KEY_LENGTH, including the varchar(64) migration caveat for the latter Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
Author
🚨 Critical Bug: IntegrityError in Production for Non-Routable IP Environments
⚡ Architectural Flaw:
|
From the review feedback on PR #5, two points accepted: - Resolve AUTHLINK_ADAPTER_CLASS per request in the whitelist middleware instead of binding the adapter at import time, matching how the views resolve it; regression test included (fails against the old middleware when another test imports the module first) - Document in the README security section that django-ipware trusts forgeable proxy headers by default, and that the reverse proxy must strip/overwrite them (or ipware trusted-proxy options be used) for IP matching to be meaningful Declined (with reasons in the PR discussion): making AuthLink.ipaddress nullable would weaken the IP-binding control the library exists to provide, and hardcoding .using('default') would override deployers' database routers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
Follows up on a test-gap review of the suite. Grows the suite from 38 to 52 tests and fixes two issues the review surfaced.
New test coverage
Locationheader — the core contract of the create endpoint was never asserted; now checked with the default and a customAUTHLINK_URL_TEMPLATEX-Forwarded-ForIP extraction — the code path changed in the 2.0.0 ipware port had no proxy-header tests. New tests pin the actual ipware 7 semantics (verified empirically before writing): public XFF wins; a leftmost-private chain fails closed (None) outsideDEBUG; a wholly-private XFF falls back toREMOTE_ADDR; plus XFF-based IP matchingAuthLinkBackendinvariant —authenticate()returnsNoneeven for valid credentials (the backend is a session tag, not a real authenticator); closes the last uncovered line in the packageAUTHLINK_NON_SUCCESS_REDIRECT_URLoverrideAUTHLINK_KEY_LENGTHoverridePOST /api/authlink/→ fresh session consumes the returnedLocation→ whitelisted URL 200, everything else 403Fixes
transaction.atomicbut without a row lock, so two simultaneous requests could both consume a link. The view now fetches withselect_for_update()(no-op on SQLite, real lock on PostgreSQL/MySQL)AUTHLINK_NON_SUCCESS_REDIRECT_URLandAUTHLINK_KEY_LENGTHwere undocumented; the latter now carries the caveat that the shipped migration isvarchar(64), so values above 64 require a project-level migrationTest plan
🤖 Generated with Claude Code