fix(#5,#36): Fix critical security issues and add comprehensive tests

SECURITY FIXES:
- Replace generic Error with UnauthorizedException in all controllers
- Fix workspace isolation bypass in findAll methods (CRITICAL)
- Controllers now always use req.user.workspaceId, never allow query override

CODE FIXES:
- Fix redundant priority logic in tasks.service.ts
- Use TaskPriority.MEDIUM as default instead of undefined

TEST ADDITIONS:
- Add multi-tenant isolation tests for all services (tasks, events, projects)
- Add database constraint violation handling tests (P2002, P2003, P2025)
- Add missing controller error tests for events and projects controllers
- All new tests verify authentication and workspace isolation

RESULTS:
- All 247 tests passing
- Test coverage: 94.35% (exceeds 85% requirement)
- Critical security vulnerabilities fixed

Fixes #5
Refs #36

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-01-28 18:55:07 -06:00
parent 132fe6ba98
commit a220c2dc0a
10 changed files with 417 additions and 21 deletions

View File

@@ -9,6 +9,7 @@ import {
Query,
UseGuards,
Request,
UnauthorizedException,
} from "@nestjs/common";
import { TasksService } from "./tasks.service";
import { CreateTaskDto, UpdateTaskDto, QueryTasksDto } from "./dto";
@@ -33,7 +34,7 @@ export class TasksController {
const userId = req.user?.id;
if (!workspaceId || !userId) {
throw new Error("User workspaceId or userId not found");
throw new UnauthorizedException("Authentication required");
}
return this.tasksService.create(workspaceId, userId, createTaskDto);
@@ -45,7 +46,10 @@ export class TasksController {
*/
@Get()
async findAll(@Query() query: QueryTasksDto, @Request() req: any) {
const workspaceId = req.user?.workspaceId || query.workspaceId;
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
return this.tasksService.findAll({ ...query, workspaceId });
}
@@ -57,7 +61,7 @@ export class TasksController {
async findOne(@Param("id") id: string, @Request() req: any) {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new Error("User workspaceId not found");
throw new UnauthorizedException("Authentication required");
}
return this.tasksService.findOne(id, workspaceId);
}
@@ -76,7 +80,7 @@ export class TasksController {
const userId = req.user?.id;
if (!workspaceId || !userId) {
throw new Error("User workspaceId not found");
throw new UnauthorizedException("Authentication required");
}
return this.tasksService.update(id, workspaceId, userId, updateTaskDto);
@@ -92,7 +96,7 @@ export class TasksController {
const userId = req.user?.id;
if (!workspaceId || !userId) {
throw new Error("User workspaceId not found");
throw new UnauthorizedException("Authentication required");
}
return this.tasksService.remove(id, workspaceId, userId);