diff --git a/openspec/changes/code-review-fix/tasks.md b/openspec/changes/code-review-fix/tasks.md index c940e99..603fad8 100644 --- a/openspec/changes/code-review-fix/tasks.md +++ b/openspec/changes/code-review-fix/tasks.md @@ -14,7 +14,7 @@ - [x] 2.1 `[haiku]` Validate `run_id` matches `/^[a-zA-Z0-9_-]+$/` in `src/app/api/training/runs/[run_id]/route.ts` before interpolation - [x] 2.2 `[sonnet]` Validate `run_id` format and use `Path.resolve()` + directory containment check in `services/ml/app/main.py` (model load at line 1203, delete at line 1312) - [x] 2.3 `[sonnet]` Add file size check (reject >10MB) and row count limit (500,000) to `src/app/api/upload/route.ts` -- [ ] 2.4 `[haiku]` Add file type validation (`.csv` extension, text MIME type) to `src/app/api/upload/route.ts` +- [x] 2.4 `[haiku]` Add file type validation (`.csv` extension, text MIME type) to `src/app/api/upload/route.ts` - [ ] 2.5 `[haiku]` Fix CORS in `services/ml/app/main.py`: replace `allow_origins=["*"]` with `["http://localhost:3000"]` and support `CORS_ORIGINS` env var ## 3. Authentication diff --git a/src/app/api/upload/route.ts b/src/app/api/upload/route.ts index 2b21213..e629a66 100644 --- a/src/app/api/upload/route.ts +++ b/src/app/api/upload/route.ts @@ -36,6 +36,24 @@ export async function POST(request: NextRequest): Promise { ); } + // Validate file type + const fileName = file.name.toLowerCase(); + if (!fileName.endsWith('.csv')) { + return NextResponse.json( + { error: 'Invalid file type. Only CSV files are accepted.' }, + { status: 400 } + ); + } + + const mimeType = file.type; + const isValidMimeType = mimeType.startsWith('text/') || mimeType === 'application/csv' || mimeType === 'text/csv'; + if (!isValidMimeType) { + return NextResponse.json( + { error: 'Invalid file type. Only CSV files are accepted.' }, + { status: 400 } + ); + } + const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB if (file.size > MAX_FILE_SIZE) { return NextResponse.json(