fix(purchases): align token cancel path with session path and guard in-flight rows (closes #645) - #648
Conversation
…n-flight rows The token/email cancel path (loadCancelableExecution) only rejected completed/cancelled, so an email-link holder could cancel an approved/running/paused/failed/expired execution that the dashboard session path refuses. Cancelling an approved/running row is unsafe: the AWS commitment is being or has been created, so the cancel would leave the DB and the cloud out of sync. Restrict the token path to pending/notified only, matching cancelPurchaseViaSession. This restriction is itself the in-flight guard. Add table-driven tests on both the token (Manager.CancelExecution) and session (cancelPurchaseViaSession) paths covering every status: each non-cancelable status is rejected with no store write, and pending/notified still cancel successfully. Closes #645
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughCentralizes cancelability in PurchaseExecution.IsCancelable(), uses it in both token and session cancel guards, and adds manager- and handler-level regression tests for allowed (pending/notified) and disallowed statuses. ChangesExecution Cancelability Alignment
🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/purchase/approvals.go (1)
191-199: ⚡ Quick winCentralize the cancelable-status predicate to prevent policy drift.
This guard now correctly matches the session path, but the
"pending"/"notified"rule is still duplicated across paths. Please consider extracting a shared predicate/constant and reusing it in both flows to avoid reintroducing asymmetric behavior in future edits.🤖 Prompt for 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. In `@internal/purchase/approvals.go` around lines 191 - 199, Extract the "cancelable" predicate into a single shared symbol and use it in both places: replace the inline status check (if execution.Status != "pending" && execution.Status != "notified") with a call to a new helper (e.g., func IsCancelableExecution(status string) bool) or a package-level constant slice/set and reuse that same helper in cancelPurchaseViaSession so both flows share identical logic; ensure the helper is located in the same package (internal/purchase) and update both call sites to use IsCancelableExecution(execution.Status) to prevent duplication and future drift.
🤖 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.
Nitpick comments:
In `@internal/purchase/approvals.go`:
- Around line 191-199: Extract the "cancelable" predicate into a single shared
symbol and use it in both places: replace the inline status check (if
execution.Status != "pending" && execution.Status != "notified") with a call to
a new helper (e.g., func IsCancelableExecution(status string) bool) or a
package-level constant slice/set and reuse that same helper in
cancelPurchaseViaSession so both flows share identical logic; ensure the helper
is located in the same package (internal/purchase) and update both call sites to
use IsCancelableExecution(execution.Status) to prevent duplication and future
drift.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 94a13b8e-e91a-450a-97b8-c26d1c349643
📒 Files selected for processing (3)
internal/api/handler_purchases_test.gointernal/purchase/approvals.gointernal/purchase/approvals_test.go
Extract the pending/notified cancelability rule into a single PurchaseExecution.IsCancelable method and call it from both cancel paths (purchase.Manager.loadCancelableExecution and the session-authed cancelPurchaseViaSession) so the policy can never drift between the token and session flows. Behavior is unchanged: only pending/notified rows stay cancelable; approved/running and other in-flight states remain non-cancelable. Addresses CodeRabbit nitpick on PR #648 (issue #645).
|
Addressed the nitpick: centralized the @coderabbitai review |
|
Triggering a review of commit ✅ Actions performedReview triggered.
|
Summary
The token/email cancel path (
loadCancelableExecution,internal/purchase/approvals.go) only rejectedcompleted/cancelled, so it allowed cancellingapproved/running/paused/failed/expiredrows. The session path (cancelPurchaseViaSession) rejects everything exceptpending/notified. This was both a privilege asymmetry (an email-link holder could cancel rows the dashboard refuses) and a missing in-flight guard (cancelling anapproved/runningrow mid-execution desyncs DB and cloud).Fix
Replaced the token-path predicate with
Status != "pending" && Status != "notified", mirroring the session path. Genuinely-pending rows still cancel normally; mid-execution rows are now rejected on both paths.Test plan
go vet+ gofmt clean; cancel tests (37) + full internal/api (1191) passCloses #645.
Summary by CodeRabbit
Bug Fixes
Tests
Refactor