Conversation
The resume-serving routes leaked candidate PII. The main file route (src/app/api/resumes/[...objectName]/route.ts) had zero auth, and the preview route authenticated but never checked ownership — anyone with an object path could fetch any applicant's resume. - New shared guard src/lib/resume/access.ts: authorizeResumeRequest() (session -> org -> applicant ownership) + resumeObjectBelongsToOrg(). Cross-org access returns 404 (not 403) so the route never leaks the existence of another workspace's resume. - Both resume routes call the guard first and stay thin; main route pinned to runtime="nodejs". - Unaffected paths: worker parsing reads disk/DB directly (HTTP fetch only for external GCS/S3 URLs); browser requests carry the session cookie so inline viewing still works. - Tests: access.test.ts (7) + route.test.ts (3 boundary) prove 401-and-file-never-read / 404 cross-org / 200 owned; upload.test.ts mocks auth+ownership for the storage round-trip. 206 tests pass. Closes #102
fix(resume): require auth + org ownership on /api/resumes/* routes
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThe PR adds a shared resume access helper, updates both resume-serving routes to use it, adds route and helper tests, and expands a storage upload test’s Prisma/auth mocks. ChangesResume access authorization
Sequence Diagram(s)sequenceDiagram
participant ResumeRoute as GET /api/resumes/[...objectName]
participant AuthorizeResumeRequest as authorizeResumeRequest
participant Auth as auth()
participant PrismaUserFindUnique as prisma.user.findUnique
participant ResumeObjectBelongsToOrg as resumeObjectBelongsToOrg
participant PrismaApplicantFindFirst as prisma.applicant.findFirst
participant ReadResumeObject as readResumeObject
ResumeRoute->>AuthorizeResumeRequest: authorizeResumeRequest(storedObjectName)
AuthorizeResumeRequest->>Auth: auth()
AuthorizeResumeRequest->>PrismaUserFindUnique: lookup session.user.email
AuthorizeResumeRequest->>ResumeObjectBelongsToOrg: verify object ownership
ResumeObjectBelongsToOrg->>PrismaApplicantFindFirst: find matching resumeUrl
AuthorizeResumeRequest-->>ResumeRoute: ok or error status
ResumeRoute->>ReadResumeObject: read stored object on success
Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Summary by CodeRabbit
New Features
Bug Fixes