Skip to content

fix: enforce ONE_TIME pre-approvals as single-use#44

Merged
ankitsejwal merged 2 commits into
mainfrom
fix/one-time-pre-approval
Jul 2, 2026
Merged

fix: enforce ONE_TIME pre-approvals as single-use#44
ankitsejwal merged 2 commits into
mainfrom
fix/one-time-pre-approval

Conversation

@ankitsejwal

Copy link
Copy Markdown
Member

Bug (found while testing PR #43): a ONE_TIME pre-approval was reusable. The redeem route only checked maxUses (null = unlimited) and never enforced the ONE_TIME semantic, so a one-time code stayed Active and redeemable after use.

Fix

  • New shared helper preApprovalRedeemError(pa, nowMs) → returns the failure reason (invalid or inactive code / code expired / code exhausted) or null. ONE_TIME → effective max 1 use, regardless of maxUses. Checks in order: inactive → expired → exhausted.
  • Redeem route now routes through it (status codes preserved: inactive→404, expired/exhausted→410).

Verified

  • Unit (8 cases): fresh ONE_TIME → ok; used ONE_TIME (maxUses null) → exhausted; inactive/expired; ALWAYS unlimited; SCHEDULED honors maxUses; expiry checked before exhaustion. 66 api tests pass.
  • E2E (live Neon): used ONE_TIME code → 410 code exhausted; fresh code → 201 then 410 on reuse; bogus → 404.
  • Full gate green.

Adds preApprovalRedeemError(pa, now) returning the failure reason (inactive /
expired / exhausted) or null. ONE_TIME codes are single-use regardless of
maxUses. Covered by a unit-test matrix.
The redeem route only checked maxUses (null = unlimited), so a ONE_TIME code
stayed redeemable after use. Route the eligibility check through the shared
preApprovalRedeemError helper, which treats ONE_TIME as effective max 1.
@ankitsejwal ankitsejwal merged commit 4da952e into main Jul 2, 2026
1 check passed
@ankitsejwal ankitsejwal deleted the fix/one-time-pre-approval branch July 2, 2026 21:39
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.

1 participant