Skip to content

Harden payment proof and session accounting checks#153

Merged
Taleef7 merged 2 commits into
mainfrom
codex/next-open-issues
Apr 27, 2026
Merged

Harden payment proof and session accounting checks#153
Taleef7 merged 2 commits into
mainfrom
codex/next-open-issues

Conversation

@Taleef7
Copy link
Copy Markdown
Owner

@Taleef7 Taleef7 commented Apr 27, 2026

Summary

  • Harden payment proof handling so saved/signed proof paths must match the authenticated payer and package prefix.
  • Add shared payment-proof upload/path helpers with unit coverage, and reuse them from the package detail flow.
  • Add local Supabase integration coverage for private payment proof storage, checkout idempotency, rejected-proof resubmission scoping, session usage RPC transitions, RPC permissions, and future-session completion blocking.
  • Update launch/docs status for payment proof RLS, package/payment idempotency, session accounting verification, and the 24-hour reschedule cutoff decision.

Verification

  • npx supabase db reset
  • npm test -- lib/payments/__tests__/proofs.test.ts lib/services/__tests__/session-status-transitions.test.ts
  • node scripts/with-local-supabase-env.mjs npm test -- supabase/__tests__/payment-session-integrity.integration.test.ts supabase/__tests__/lifecycle-rls.integration.test.ts
  • npm test
  • npm run typecheck
  • npm run lint (passes with 4 existing warnings in unrelated files)
  • node scripts/with-local-supabase-env.mjs npm run build
  • git diff --check

Closes #120
Closes #138
Closes #139
Closes #145

Copilot AI review requested due to automatic review settings April 27, 2026 01:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens payment-proof handling and session usage accounting by enforcing proof path conventions, reusing shared helpers in the student package payment flow, and adding local Supabase integration tests to validate RLS/idempotency and RPC transition behavior end-to-end.

Changes:

  • Added shared payment-proof helpers (path building, filename sanitization, MIME-type allowlist) with unit tests.
  • Enforced payer/package-bound proof-path validation when saving payment details, resubmitting rejected payments, and generating signed URLs.
  • Added local Supabase integration coverage for private proof storage access rules, checkout idempotency, rejected-proof resubmission scoping, and session usage RPC correctness/permissions; updated launch/docs checklists accordingly.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
supabase/tests/payment-session-integrity.integration.test.ts New local-Supabase integration tests covering storage privacy/idempotency and session accounting RPC behavior.
lib/payments/proofs.ts Introduces shared helpers/constants for payment proof validation and storage path construction.
lib/payments/tests/proofs.test.ts Unit tests for the new proof helper functions.
app/dashboard/packages/actions.ts Adds proof-path validation when signing/saving/resubmitting proofs.
app/dashboard/packages/[id]/page.tsx Reuses shared helpers for proof upload validation/path building in the package payment UI.
docs/plan-CorvEd.md Updates launch-plan checklist items to reflect new coverage/verification steps.
docs/OPS.md Updates ops guidance around documenting reschedule cutoff exceptions.
docs/MVP.md Documents the decision to warn (not hard-block) inside the 24-hour cutoff and adds integrity-check commands.
docs/GAP_ANALYSIS.md Updates resolved items to cite new validation and integration test verification.
docs/ARCHITECTURE.md Documents proof path convention and verification command for local integrity tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +254 to +258
const { data: stillPrivateProof, error: stillPrivateProofError } = await student.client.storage
.from('payment-proofs')
.download(proofPath)
expect(stillPrivateProofError).toBeNull()
expect(await stillPrivateProof?.text()).toBe('proof')
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The assertions after remove([proofPath]) are internally inconsistent: if the delete succeeds (deleteError is null), the subsequent download(proofPath) should fail (object no longer exists). Either assert that deletion is denied (and keep the download expectation), or keep the successful delete expectation and assert the download returns an error / null data.

Suggested change
const { data: stillPrivateProof, error: stillPrivateProofError } = await student.client.storage
.from('payment-proofs')
.download(proofPath)
expect(stillPrivateProofError).toBeNull()
expect(await stillPrivateProof?.text()).toBe('proof')
const { data: deletedProof, error: deletedProofError } = await student.client.storage
.from('payment-proofs')
.download(proofPath)
expect(deletedProofError).toBeTruthy()
expect(deletedProof).toBeNull()

Copilot uses AI. Check for mistakes.
Comment thread docs/OPS.md Outdated
# CorvEd Ops

Last updated: 2026-02-22
Last updated: 2026-04-27
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

Markdown formatting: the Last updated: line no longer ends with the two trailing spaces used by the other header metadata lines in this doc, so it will render on the same line as Owner:. Consider restoring the trailing spaces (or converting these header fields to a bullet list) for consistent rendering.

Suggested change
Last updated: 2026-04-27
Last updated: 2026-04-27

Copilot uses AI. Check for mistakes.
Comment thread docs/ARCHITECTURE.md Outdated
# CorvEd architecture

Last updated: 2026-02-22
Last updated: 2026-04-27
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

Markdown formatting: Last updated: is now missing the trailing two spaces used elsewhere in this doc’s header metadata, so it will render inline with Stack:. Consider adding consistent line-break formatting (e.g., trailing two spaces on each metadata line or switching to a list) so the header doesn’t collapse into a single paragraph.

Suggested change
Last updated: 2026-04-27
Last updated: 2026-04-27

Copilot uses AI. Check for mistakes.
@Taleef7
Copy link
Copy Markdown
Owner Author

Taleef7 commented Apr 27, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 27, 2026

@copilot apply changes based on the comments in this thread

Applied all three changes in commit 5bceb41:

  1. Integration test (supabase/__tests__/payment-session-integrity.integration.test.ts): Fixed the inconsistent post-delete assertions — after a successful remove(), the download() now asserts deletedProofError is truthy and deletedProof is null (the object no longer exists).

  2. docs/OPS.md and docs/ARCHITECTURE.md: Restored the trailing two spaces on the Last updated: lines so they render as proper line breaks consistent with the other metadata lines.

@Taleef7 Taleef7 merged commit 90ffe44 into main Apr 27, 2026
1 check passed
@Taleef7 Taleef7 deleted the codex/next-open-issues branch April 27, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants