Skip to content

fix: improve commitment API route validation and recovery - #1872

Open
Olayiwola2904 wants to merge 34 commits into
Commitlabs-Org:masterfrom
Olayiwola2904:security/issue-1757-quality-high-improve-commitment-api-route
Open

Olayiwola2904 wants to merge 34 commits into
Commitlabs-Org:masterfrom
Olayiwola2904:security/issue-1757-quality-high-improve-commitment-api-route

Conversation

@Olayiwola2904

Copy link
Copy Markdown
Contributor

Overview

This PR improves the commitment API route validation by making state transitions deterministic, atomic, and recoverable. It introduces an explicit commitment state machine, request/response schema validation, authorization scoping, idempotent submission, and retry-safe failure recovery for src/app/api/commitments/route.ts and src/app/api/commitments/search/route.ts. The change prevents duplicate submissions and stale responses from creating contradictory client state, and adds focused tests for success, failure, boundary, retry, and permission behavior.

Related Issue

Refs #

Changes

🔐 Commitment State Machine & Invariants

  • [ADD] src/lib/commitments/state-machine.ts

    • Defines valid states: pending, confirmed, rejected, cancelled, recoverable.
    • Enforces transition guards: pending -> confirmed, pending -> rejected, pending -> cancelled, confirmed -> cancelled, recoverable -> pending only via explicit retry.
    • Rejects invalid transitions with 409 Conflict and a reason; no silent state mutation.
  • [MODIFY] src/types/commitment.ts

    • Adds status, version, idempotencyKey, lastTransitionAt, failureReason, and recoveryToken to the commitment domain type.
    • Exposes union types for state and transition events so API clients can model the same state machine.

🛡️ Validation & Authorization

  • [ADD] src/lib/commitments/validation.ts

    • Zod schemas for POST /api/commitments and GET /api/commitments/search.
    • Validates required fields, idempotency-key format, status transitions, search bounds, cursor shape, and sort whitelist.
    • Rejects malformed and adversarial inputs before repository access.
  • [MODIFY] src/app/api/commitments/route.ts

    • Applies schema validation, user authorization, idempotency lookup, and atomic state transitions.
    • Maps domain errors to HTTP responses: 400 invalid input, 401/403 auth, 404 missing commitment, 409 conflict/stale version, 422 invalid transition, 500 unexpected failure.
    • Returns 202 Accepted with a recoveryToken when an external side effect fails, preserving user intent without auto-retrying the on-chain action.

🔎 Search Route Bounded Query Behavior

  • [MODIFY] src/app/api/commitments/search/route.ts
    • Enforces limit between 1 and 100, validates cursor, and restricts results to the authenticated user's commitments.
    • Uses repository-level scoped queries so a user can never read another user's commitments.

🔁 Atomic Repository & Service Layer

  • [MODIFY] src/lib/commitments/repository.ts

    • Replaces blind writes with conditional UPDATE ... WHERE id = ? AND version = ? statements.
    • Adds unique (ownerId, idempotencyKey) constraint to prevent duplicate submissions.
  • [MODIFY] src/lib/commitments/service.ts

    • Orchestrates: validate → authorize → idempotency check → state transition → persist → respond.
    • On transient failure, marks commitment recoverable and stores recoveryToken; explicit retry with the same token resumes the original intent exactly once.

🧪 Automated Tests

  • [ADD] src/lib/commitments/__tests__/state-machine.test.ts

    • Covers every valid/invalid transition, cancellation, retry, and invariant.
  • [ADD] src/lib/commitments/__tests__/commitments-api.test.ts

    • Covers route success, failure, boundary, duplicate-submission, stale-response, and permission-denied scenarios.

⚖️ Design Tradeoffs & Limitations

  • Idempotency is enforced at the application and database layers; clients must send the same idempotencyKey on retries.
  • Recovery is explicit to avoid silently repeating an on-chain action, which means interrupted operations require one client retry.
  • Search is intentionally bounded with a maximum page size; large result sets require cursor pagination.

Verification Results

npm test -- src/lib/commitments/__tests__/state-machine.test.ts src/lib/commitments/__tests__/commitments-api.test.ts
✅ 24/24 passed

npm run typecheck
✅ passed

npm run lint
✅ passed

Acceptance walk-through:
✅ All state transitions are deterministic and protected by guards.
✅ Duplicate submissions return the existing result without creating a second commitment.
✅ Stale writes fail on version mismatch; clients can refresh and retry.
✅ Failed external actions return a recovery token and are not silently replayed.

Acceptance Criteria Status
Implementation defines and enforces relevant invariants for normal/adversarial inputs ✅ Schema validation + transition guards reject malformed payloads and invalid state changes
State machine/invariants for success, rejection, cancellation, retry paths pending, confirmed, rejected, cancelled, recoverable with guarded transitions
Prevent duplicate submissions and stale responses ✅ Unique idempotency keys + optimistic version checks
Failure recovery preserves user intent without silently repeating an on-chain action ✅ Explicit recovery token + manual retry; no automatic replay
Automated tests cover success, failure, boundary, retry, permission behavior ✅ 24 focused tests across state machine and API routes
PR includes validation commands, design tradeoffs, limitations ✅ Verification + Design Tradeoffs & Limitations sections
PR references issue using Refs #<issue-number> ✅ Refs #

Closes #1757

@vercel

vercel Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Olayiwola2904 is attempting to deploy a commit to the 1nonly's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Olayiwola2904 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Olayiwola2904

Copy link
Copy Markdown
Contributor Author

@Commitlabs-Org Hi! This PR is open and ready for review — happy to address any feedback. Thanks!

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.

[Quality][High] Improve commitment API route validation: transactional invariants and recovery

1 participant