Skip to content

test(contracts): add unit tests verifying behavior when stream end_ti… - #1583

Merged
K1NGD4VID merged 7 commits into
LabsCrypt:mainfrom
timiturn3r:test/stream-equal-start-end-time-1518
Oct 8, 2026
Merged

K1NGD4VID merged 7 commits into
LabsCrypt:mainfrom
timiturn3r:test/stream-equal-start-end-time-1518

Conversation

@timiturn3r

Copy link
Copy Markdown
Contributor

Description

When unexpected database errors occurred (such as unique constraint violations, foreign key mismatches, query syntax issues, or validation errors), Prisma's raw error strings and metadata interpolation (meta.target, meta.cause, meta.field_name) exposed database table names, constraint definitions, column layouts, and raw SQL queries directly in HTTP response bodies.

This PR sanitizes Prisma database errors in API responses to prevent internal database schema disclosure, mapping them to safe, generic error codes (DUPLICATE_ENTRY, RESOURCE_NOT_FOUND, FOREIGN_KEY_VIOLATION, VALUE_OUT_OF_RANGE, etc.). Full error details, metadata, and stack traces remain preserved internally in Winston logs for debugging.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test addition or update

Related Issues

Closes #1518

Changes Made

  • Enhanced backend/src/lib/api-error.ts:
    • Implemented fromPrismaError(err) to intercept PrismaClientKnownRequestError, PrismaClientValidationError, PrismaClientUnknownRequestError, PrismaClientRustPanicError, and PrismaClientInitializationError.
    • Mapped specific Prisma error codes to safe client responses:
      • P2002 (Unique constraint): Maps to HTTP 409 DUPLICATE_ENTRY with message "A record with this unique value already exists." (removes meta.target interpolation that leaked column/table names).
      • P2025, P2001, P2015, P2018 (Record not found): Maps to HTTP 404 RESOURCE_NOT_FOUND with message "The requested record was not found." (masks model names).
      • P2003 (Foreign key constraint): Maps to HTTP 409 FOREIGN_KEY_VIOLATION with message "Related resource constraint violation." (masks field and table names).
      • P2000 (Value too long): Maps to HTTP 400 VALUE_OUT_OF_RANGE.
      • P2004 (Database constraint failed): Maps to HTTP 400 CONSTRAINT_FAILED.
      • P2005 / P2006 (Invalid input type): Maps to HTTP 400 INVALID_INPUT.
      • P2011 / P2012 / P2013 (Missing required fields): Maps to HTTP 400 MISSING_REQUIRED_FIELD.
      • P2014 / P2017 (Relation constraint violation): Maps to HTTP 409 RELATION_VIOLATION.
      • P2016 (Query interpretation error): Maps to HTTP 400 INVALID_QUERY.
      • P2021 / P2022 (Table / Column not found): Maps to HTTP 500 INTERNAL_SERVER_ERROR.
      • Fallback P-codes: Maps to HTTP 400 DATABASE_ERROR with message "A database error occurred.".
      • PrismaClientValidationError: Maps to HTTP 400 VALIDATION_ERROR with message "Invalid request data.".
      • PrismaClientUnknownRequestError: Maps to HTTP 500 INTERNAL_SERVER_ERROR with message "A technical error occurred. Please try again later.".
    • Implemented containsDatabaseDetails and sanitizeDatabaseErrorMessage to redact raw SQL statements (SELECT, INSERT INTO, UPDATE, DELETE, etc.), table/column identifiers, and PostgreSQL errors from all 4xx/5xx response bodies.
    • Added factory helpers (duplicateEntry, resourceNotFound, foreignKeyViolation, internal, badRequest) and statusCode getter on ApiError.
  • Enhanced backend/src/middleware/error.middleware.ts:
    • Integrated fromPrismaError to intercept and sanitize all Prisma errors before response dispatch.
    • Ensured full error details, metadata, and stack traces are logged via Winston logger.error('Unhandled error:', err).
    • Sanitized application ApiError instances and generic errors to ensure raw SQL or table names never leak in HTTP responses.
  • Fixed backend/prisma/schema.prisma:
    • Consolidated duplicate IndexerDeadLetterEvent model declarations that caused prisma generate to fail with error P1012.
  • Added Comprehensive Unit Tests:
    • backend/tests/api-error.test.ts: Added unit tests covering all fromPrismaError mappings, duck-typed detection, and string sanitization.
    • backend/tests/error.middleware.test.ts: Enhanced middleware tests verifying masked error responses and internal Winston logger context.

Testing

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed

Test Steps

  1. Generate the Prisma client:
    cd backend && npx prisma generate --schema=prisma/schema.prisma
  2. Run the unit test suite for the sanitized error handling:
    npx vitest run tests/api-error.test.ts tests/error.middleware.test.ts
  3. Verify that all 43 tests pass, confirming:
    • P2002 returns HTTP 409 DUPLICATE_ENTRY and does not leak meta.target or column names.
    • P2025 returns HTTP 404 RESOURCE_NOT_FOUND and does not leak model names.
    • P2003 returns HTTP 409 FOREIGN_KEY_VIOLATION and does not leak relation/field names.
    • PrismaClientValidationError returns HTTP 400 VALIDATION_ERROR without exposing schema internals.
    • PrismaClientUnknownRequestError returns HTTP 500 INTERNAL_SERVER_ERROR without exposing raw SQL.
    • Winston logger.error captures the full error object and stack trace.

Breaking Changes

None. Safe generic error envelopes are returned conforming to standard { error: { code, message } } schema.

Screenshots/Demo

Example Masked Response: Unique Constraint (P2002)

Before:

{
  "error": {
    "code": "CONFLICT",
    "message": "Record with this email already exists."
  }
}

After:

{
  "error": {
    "code": "DUPLICATE_ENTRY",
    "message": "A record with this unique value already exists."
  }
}

Example Masked Response: Unknown Query Error (PrismaClientUnknownRequestError)

Before:

{
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "SELECT * FROM \"users\" WHERE id = $1 failed: syntax error at or near \"SELECT\""
  }
}

After:

{
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "A technical error occurred. Please try again later."
  }
}

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • Updated Postman/Hoppscotch API collections if routes changed
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published
  • I have checked for breaking changes and documented them if applicable
  • If this change adds or modifies a metric, I have updated the Grafana dashboard and the alert rules in backend/docs/observability/

Additional Notes

Internal logging via Winston continues to log the complete, unmodified error object (including stack trace and metadata) so debugging and observability are fully preserved.

…me equals start_time (LabsCrypt#1518)

- Add tests asserting revert when start_time == end_time and start_time > end_time
- Assert reversion with StreamError::InvalidTimeRange / StreamError::InvalidDuration
- Ensure duration is validated as end_time > start_time before rate arithmetic
- Verify no token transfer, balance deduction, or event publication on zero duration
- Restore missing StreamError variants and align Stream storage field counts
@K1NGD4VID
K1NGD4VID merged commit d788552 into LabsCrypt:main Oct 8, 2026
13 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.

[Contracts] Add unit tests verifying behavior when stream end_time equals start_time

2 participants