Skip to content

fix(api): enforce password length and upload content validation - #84

Merged
mankatcheung merged 1 commit into
mainfrom
fix/api-input-validation
Jul 25, 2026
Merged

mankatcheung merged 1 commit into
mainfrom
fix/api-input-validation

Conversation

@mankatcheung

@mankatcheung mankatcheung commented Jul 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

Follow-up to a validation audit of apps/api's interface-adapters layer. The audit found validation was thin and inconsistent across the API — this PR fixes the two highest-value, lowest-risk gaps that were flagged:

  • Password length was inconsistent. ResetPasswordUseCase enforced PASSWORD_MIN_LENGTH (8 chars), but RegisterUseCase and UpdatePasswordUseCase didn't check length at all — a user could register or change their password to a single character. Extracted the check into use-cases/auth/passwordValidation.ts (a plain same-layer helper, mirroring the existing use-cases/jobs/bulkValidation.ts pattern — not a new port/abstraction) and wired it into all three password-writing use cases.
  • Upload flow validated authorization but not content. requestUploadUrl and confirmDocument never checked mimeType against an allow-list, and confirmDocument's sizeBytes accepted negative or unbounded values. Added use-cases/documents/documentValidation.ts with ALLOWED_DOCUMENT_MIME_TYPES (pdf/doc/docx/txt/png/jpeg, matching the document types the web app's upload UI actually offers) and MAX_DOCUMENT_SIZE_BYTES (10MB) in constants.ts, enforced in both use cases.

Clean Architecture: all new validation logic lives in the use-cases layer, next to the business logic it guards — no interface-adapters (resolvers) or infrastructure (Prisma repos) files were touched. The new helper modules are plain functions imported by sibling use-cases within the same layer, not new port interfaces, since they don't need to cross a layer boundary.

Deliberately out of scope (from the same audit, not part of this fix): email format validation, documentType enum-ification, free-text length caps, date-string validation, and MCP tool parameter validation — larger/lower-priority items not requested for this pass.

Test plan

  • pnpm --filter @job-finder/api test — 667 tests passing (7 new, covering the new validation paths)
  • pnpm --filter @job-finder/api typecheck — clean
  • pnpm --filter @job-finder/api lint — clean
  • Updated existing test fixtures that used sub-8-char passwords (unrelated to what those tests were actually verifying)

Note: one pre-existing, unrelated flaky test (PrismaDocumentRepository — SQLite millisecond-resolution timestamp ordering) was observed during verification; not touched by this PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added validation for password length during registration, password updates and password resets.
    • Added document upload validation for supported file types and file sizes up to 10 MB.
    • Invalid inputs are rejected before database or storage operations begin.
  • Tests

    • Expanded coverage for invalid passwords, MIME types, document sizes and early validation failures.

Follow-up to a validation audit of the interface-adapters layer. Two
concrete, highest-value gaps:

Password length was only enforced on the reset-password flow
(PASSWORD_MIN_LENGTH), not on register or change-password, so a user
could set a 1-character password through either of those paths.
Extracted the check into use-cases/auth/passwordValidation.ts (mirrors
the existing use-cases/jobs/bulkValidation.ts pattern — a plain
same-layer helper, not a new port) and wired it into all three
password-writing use cases.

The document-upload flow validated authorization but not content:
mimeType wasn't checked against any allow-list at requestUploadUrl or
confirmDocument, and confirmDocument's sizeBytes accepted negative or
unbounded values. Added use-cases/documents/documentValidation.ts with
an allow-list (ALLOWED_DOCUMENT_MIME_TYPES) and a size cap
(MAX_DOCUMENT_SIZE_BYTES, 10MB) in constants.ts, enforced in both use
cases.

All validation stays in the use-cases layer, consistent with Clean
Architecture — interface-adapters (resolvers) and infrastructure
(Prisma repos) are untouched; only business-rule checks were added
where business logic already lives.
@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7d616725-5f23-4ba0-858b-59f44b546458

📥 Commits

Reviewing files that changed from the base of the PR and between 2630587 and 4d63109.

📒 Files selected for processing (13)
  • apps/api/src/__tests__/application/auth/RegisterUseCase.test.ts
  • apps/api/src/__tests__/application/documents/ConfirmDocumentUseCase.test.ts
  • apps/api/src/__tests__/application/documents/RequestUploadUrlUseCase.test.ts
  • apps/api/src/__tests__/application/user/UpdatePasswordUseCase.test.ts
  • apps/api/src/__tests__/security/authorizationGuards.test.ts
  • apps/api/src/constants.ts
  • apps/api/src/use-cases/auth/RegisterUseCase.ts
  • apps/api/src/use-cases/auth/ResetPasswordUseCase.ts
  • apps/api/src/use-cases/auth/passwordValidation.ts
  • apps/api/src/use-cases/documents/ConfirmDocumentUseCase.ts
  • apps/api/src/use-cases/documents/RequestUploadUrlUseCase.ts
  • apps/api/src/use-cases/documents/documentValidation.ts
  • apps/api/src/use-cases/user/UpdatePasswordUseCase.ts

Walkthrough

The change centralises password and document validation, applies checks before repository operations, and adds tests for invalid passwords, MIME types, and file sizes.

Changes

Input validation

Layer / File(s) Summary
Shared password validation
apps/api/src/use-cases/auth/passwordValidation.ts, apps/api/src/use-cases/auth/*.ts, apps/api/src/use-cases/user/UpdatePasswordUseCase.ts, apps/api/src/__tests__/application/auth/RegisterUseCase.test.ts, apps/api/src/__tests__/application/user/UpdatePasswordUseCase.test.ts, apps/api/src/__tests__/security/authorizationGuards.test.ts
Password validation is shared across registration, reset, and update flows, with short-password and guard scenarios covered by tests.
Document upload validation
apps/api/src/constants.ts, apps/api/src/use-cases/documents/documentValidation.ts, apps/api/src/use-cases/documents/*.ts, apps/api/src/__tests__/application/documents/*.test.ts
Allowed MIME types and maximum size are enforced before application lookups or document creation, with invalid-input tests added.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Poem

A rabbit checks each password string,
And guards each file that users bring.
Too short? Too large? Wrong type? No pass—
The repositories stay untouched en masse.
Validation hops ahead with cheer,
Keeping every input clear.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/api-input-validation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mankatcheung
mankatcheung marked this pull request as ready for review July 25, 2026 10:34
@mankatcheung
mankatcheung merged commit ab23753 into main Jul 25, 2026
5 checks passed
@mankatcheung
mankatcheung deleted the fix/api-input-validation branch July 25, 2026 10: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

Development

Successfully merging this pull request may close these issues.

1 participant