Skip to content

Agent: Harden payment endpoint authorization and state transitions - #30

Merged
matteius merged 2 commits into
opensensor:mainfrom
matteius:agent/issue-27-39052230442
Oct 17, 2026
Merged

matteius merged 2 commits into
opensensor:mainfrom
matteius:agent/issue-27-39052230442

Conversation

@matteius

Copy link
Copy Markdown
Contributor

Refs #27

Agent-generated change from a maintainer-labeled issue. Review the diff and CI results before merging. Close the issue only when its acceptance criteria are complete.

DigitalOcean session: django-forms-public-issue-27-39052230442.

opensensor-agent and others added 2 commits October 17, 2026 17:41
…or#27)

Enforce a single payment access policy on all checkout endpoints
(initiate/confirm/return/cancel): an authenticated submitter may act
only on their own submission, and an anonymous public-form submitter
needs a short-lived, unguessable, session-bound checkout credential
issued when the form post enters pending_payment. Guessed numeric IDs
now get a non-disclosing 404.

- Initiation is idempotent per attempt: repeated GETs reuse the single
  open PaymentRecord and its stable idempotency key (forwarded to
  Stripe's PaymentIntent.create) under a row lock, so retries cannot
  create uncontrolled attempts or duplicate charges. A legitimate retry
  after cancel/failure starts a fresh key.
- Confirm/return are restricted to the originating open attempt and
  valid lifecycle states; provider results are verified and applied
  without ever rolling a locked (completed/refunded) record backward.
- Cancellation is a CSRF-protected POST-only action scoped to
  pending_payment submissions; it cancels only open attempts and can
  never revert a completed/submitted/approved submission to draft.
  Templates now use POST forms for the cancel action.
- Stripe webhooks fail closed: events are rejected (HTTP 400) when
  STRIPE_WEBHOOK_SECRET is unset or the signature is invalid. The
  provider interface requires the same authenticated-event guarantee
  from all providers via the new WebhookVerificationError. Replayed or
  out-of-order events create no duplicate workflow tasks.
- Regression tests cover anonymous/stranger/owner/anonymous-checkout
  access, guessed IDs, GET vs POST, repeated requests, missing/invalid
  webhook signatures, replay protection, and cancellation after
  completion. Docs updated for the required webhook secret and the new
  checkout/idempotency behavior.
@matteius
matteius merged commit e8b9595 into opensensor:main Oct 17, 2026
5 checks passed
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