feat(security): harden the API, trust Hiboutik for deletions, lock syncs #3

Merged
quentin_duwa merged 4 commits from feature/input-validation into main 2026-11-08 09:36:50 +00:00
Owner
No description provided.
quentin_duwa added 2 commits 2026-11-08 09:12:34 +00:00
A successful (2xx) answer from Hiboutik is now the truth, even an empty
list: records missing from it are deleted. The "empty list means API
issue" safety nets are removed.

Deletion stays safe because a failed call deletes nothing: HTTP errors
throw, and the new HiboutikClient.getList (used by getAllPages and the
non-paginated lists) also throws on a 2xx body that is not a list, so a
malformed answer is never mistaken for an empty list. A 2xx without body
is an empty list.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Validate the environment at startup (src/config): required variables
  must be present, HIBOUTIK_BASE_URL must be HTTPS.
- Global ValidationPipe (whitelist, forbidNonWhitelisted, transform).
- Helmet, CORS disabled unless CORS_ORIGINS is set, TRUST_PROXY support,
  HTTP header/request timeouts, shutdown hooks.
- Rate limiting: 60 req/min/IP globally, 5 req/min on POST /sync.
- AllExceptionsFilter: unexpected errors are logged (message + stack,
  never the raw error object) and answered with a generic 500.
- Postgres advisory lock (dedicated connection) so only one
  synchronization runs at a time across all instances; released by
  Postgres itself if the process dies.
- Fix the Jest moduleNameMapper (unescaped dot also matched .cjs files).
- Document the input validation and security rules in CLAUDE.md.
- Add class-validator, class-transformer, helmet and @nestjs/throttler;
  npm audit fix refreshed package-lock.json.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
quentin_duwa added 1 commit 2026-11-08 09:21:30 +00:00
Each startSync request takes the Postgres advisory lock on its own
connection (its own session), so it already refuses concurrent calls on
the same instance: the in-process syncInProgress flag and its
isSyncInProgress getter were redundant and are removed. syncAll becomes
private: syncs start only through startSync.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
quentin_duwa added 1 commit 2026-11-08 09:34:58 +00:00
quentin_duwa merged commit 8c8a2ccf15 into main 2026-11-08 09:36:50 +00:00
quentin_duwa deleted branch feature/input-validation 2026-11-08 09:36:51 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: quentin_duwa/dinggadingga-backend#3
No description provided.