Skip to content

feat: apply strict CORS and security headers to partial-release endpoint - #399

Merged
godamongstmen897 merged 7 commits into
Goldii-locks:mainfrom
DeePrincipal-dev-lang:feat/partial-release-cors-security-headers
Sep 1, 2026
Merged

feat: apply strict CORS and security headers to partial-release endpoint#399
godamongstmen897 merged 7 commits into
Goldii-locks:mainfrom
DeePrincipal-dev-lang:feat/partial-release-cors-security-headers

Conversation

@DeePrincipal-dev-lang

Copy link
Copy Markdown
Contributor

Apply strict CORS and security headers to partial-release endpoint

Summary

Hardens the POST /api/jobs/:contractId/milestones/:index/partial-release endpoint with strict Cross-Origin Resource Sharing (CORS) enforcement and required security headers, bringing it into compliance with the repo's established security patterns used by neighboring endpoints.

What Changed

Security Middleware

  • partialReleaseCors: Enforces strict origin allowlist validation

    • Only whitelisted origins (e.g., http://localhost:3000, production domains) are allowed
    • Unauthorized origins receive 403 response with CORS policy error
    • Proper CORS response headers set for allowed origins
  • partialReleaseSecurityHeaders: Applies required response headers

    • X-Content-Type-Options: nosniff
    • X-Frame-Options: DENY
    • Referrer-Policy: no-referrer
    • X-XSS-Protection: 0
    • Content-Security-Policy: default-src 'none'
    • Permissions-Policy with camera, microphone, and other restrictions

Route Implementation

  • Added OPTIONS handler for CORS preflight requests
  • Wired partialReleaseCors and partialReleaseSecurityHeaders to both OPTIONS and POST handlers
  • Fixed source account validation logic to run before cache checks for proper error classification
  • Account fetch errors now properly translate to 404 (not found) vs 422 (contract error) vs 500

Test Coverage

  • 30 comprehensive regression tests covering:
    • Unauthorized origin rejection (403 CORS error)
    • Trusted origin acceptance with correct CORS headers
    • Security headers validation on successful responses
    • Parameter validation (contractId, index, amount, sourceAddress)
    • Error classification (account not found → 404, contract error → 422)
    • Cache hit and in-flight request dedup behavior

Cleanup

  • Removed duplicate declarations in src/indexer/db.ts that were blocking test execution
  • Cleaned up duplicate imports in test files

Testing

All 30 partial-release regression tests passing:
Test Suites: 1 passed, 1 total
Tests: 30 passed, 30 total

Validates:
✅ Unauthorized origins rejected with 403 CORS policy error
✅ Trusted origins receive proper CORS response headers
✅ Security headers set on all successful responses
✅ Account-not-found errors return 404 with proper message
✅ Cache and in-flight request dedup logic continues to work

Files Changed

  • src/middleware/job-contract-security.ts — Added partialReleaseCors and partialReleaseSecurityHeaders
  • src/routes/jobs.ts — Wired middleware, fixed route logic
  • __tests__/partial-release.test.ts — Updated test mocks and coverage
  • src/indexer/db.ts — Removed duplicate declarations
  • __tests__/sqlite-schema-manager.test.ts — Cleaned up imports

Implementation Notes

  • Follows the exact same middleware pattern as neighboring endpoints (by-wallet, build-tx, etc.)
  • Reuses repository's existing security header set for consistency
  • Error classification via classifySimError() ensures proper HTTP status codes (404/422/500)
  • Cache and dedup logic preserves request performance optimization

closes #113

- Add partialReleaseCors middleware with strict origin allowlist enforcement
- Add partialReleaseSecurityHeaders with required security headers
- Wire CORS and security middlewares to POST and OPTIONS handlers
- Fix route logic: fetch source account before cache check to ensure proper error classification
- Update partial-release tests to mock getAccount for trusted-origin regression tests
- Clean up duplicate declarations in db.ts that blocked test execution

Validates:
- Unauthorized origins rejected with 403 CORS policy error
- Trusted origins receive proper CORS response headers
- Security headers set on all successful responses
- Account-not-found errors return 404 with proper message
- Cache and in-flight request dedup logic continues to work correctly

All 30 partial-release regression tests passing.
@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@DeePrincipal-dev-lang 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

@godamongstmen897

Copy link
Copy Markdown
Contributor

@DeePrincipal-dev-lang fix failed CI check

godamongstmen897 and others added 2 commits August 31, 2026 10:29
…ter-pool

Optimize poller throttling parameters in database_writer_pool
- Re-introduce insertEvent import in poller for historical event insertion
- Tighten mock server call assertions for Jest/TypeScript compatibility
- Wrap runMigrations with proper error handling and logging
- Cast Jest mock calls to any to bypass strict tuple typing in tests
- Resolve all remaining TypeScript compiler blockers
- All legacy API contracts now satisfied for backward compatibility
@DeePrincipal-dev-lang

Copy link
Copy Markdown
Contributor Author

Cl check fixed👌

…the replays

The branch predates the indexer repairs already on main and re-adds
several of the same declarations, so the merge produced 35 type errors:
duplicate logPollDiagnostics, IndexerRunnerFailureMonitor,
verifyLedgerRangeTrackerSchema and assertLedgerRangeTrackerSchemaValid,
plus 18 more in sqlite_vacuum_cleaner.

Those six files are incidental to this PR -- its subject is CORS and
security headers on partial-release -- and main already carries the work
they duplicate, so they were taken from main:

  failover-recovery.ts, indexer_runner.ts, ledger-range-tracker.ts,
  sqlite_vacuum_cleaner.ts, event_type_filter.ts and the vacuum test

event_type_filter.ts is worth calling out: the branch widens
fetchEventsWithRetry's server parameter from Pick<Server, "getEvents">
to an inline shape typed with `any`. That is a loss of type safety
rather than a fix, so main's signature stands.

One duplicate mattered beyond compilation. The branch re-adds a
partial-release cache key and hit path that main already has, and its
key omits `amount`:

  `${contractId}:${index}:${sourceAddress}`

Two releases of different amounts against the same milestone and source
would share a cache entry, so the second caller would be handed the
first one's XDR. main's partialReleaseCacheKey() includes the amount;
its key and its hit path were kept and the branch's removed.

Kept in full: the new job-contract-security middleware, its wiring into
the partial-release route, the 58-line test addition, and the verify-ci
ESM conversion -- that last one is a real fix, since the package is
type: module and the old require() form crashed on startup.

Also ignored the *.exit files verify-ci.js writes, which were otherwise
landing as untracked build artifacts.

tsc 0 errors / 1558 tests across 88 suites / build OK
@godamongstmen897
godamongstmen897 merged commit 050d521 into Goldii-locks:main Sep 1, 2026
1 check 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.

Configure CORS and Security headers for POST /api/jobs/:contractId/milestones/:index/partial-release

3 participants