diff --git a/apps/api/src/activity/activity.service.spec.ts b/apps/api/src/activity/activity.service.spec.ts index 3c87822..3119cab 100644 --- a/apps/api/src/activity/activity.service.spec.ts +++ b/apps/api/src/activity/activity.service.spec.ts @@ -802,7 +802,7 @@ describe("ActivityService", () => { ); }); - it("should handle database errors gracefully when logging activity", async () => { + it("should handle database errors gracefully when logging activity (fire-and-forget)", async () => { const input: CreateActivityLogInput = { workspaceId: "workspace-123", userId: "user-123", @@ -814,7 +814,9 @@ describe("ActivityService", () => { const dbError = new Error("Database connection failed"); mockPrismaService.activityLog.create.mockRejectedValue(dbError); - await expect(service.logActivity(input)).rejects.toThrow("Database connection failed"); + // Activity logging is fire-and-forget - returns null on error instead of throwing + const result = await service.logActivity(input); + expect(result).toBeNull(); }); it("should handle extremely large details objects", async () => { @@ -1132,7 +1134,7 @@ describe("ActivityService", () => { }); describe("database error handling", () => { - it("should handle database connection failures in logActivity", async () => { + it("should handle database connection failures in logActivity (fire-and-forget)", async () => { const createInput: CreateActivityLogInput = { workspaceId: "workspace-123", userId: "user-123", @@ -1144,7 +1146,9 @@ describe("ActivityService", () => { const dbError = new Error("Connection refused"); mockPrismaService.activityLog.create.mockRejectedValue(dbError); - await expect(service.logActivity(createInput)).rejects.toThrow("Connection refused"); + // Activity logging is fire-and-forget - returns null on error instead of throwing + const result = await service.logActivity(createInput); + expect(result).toBeNull(); }); it("should handle Prisma timeout errors in findAll", async () => { diff --git a/apps/api/src/runner-jobs/runner-jobs.service.spec.ts b/apps/api/src/runner-jobs/runner-jobs.service.spec.ts index c53ace7..2632192 100644 --- a/apps/api/src/runner-jobs/runner-jobs.service.spec.ts +++ b/apps/api/src/runner-jobs/runner-jobs.service.spec.ts @@ -374,25 +374,32 @@ describe("RunnerJobsService", () => { id: jobId, workspaceId, status: RunnerJobStatus.PENDING, + version: 1, }; const mockUpdatedJob = { ...mockExistingJob, status: RunnerJobStatus.CANCELLED, completedAt: new Date(), + version: 2, }; - mockPrismaService.runnerJob.findUnique.mockResolvedValue(mockExistingJob); - mockPrismaService.runnerJob.update.mockResolvedValue(mockUpdatedJob); + // First findUnique returns existing job, second returns updated job + mockPrismaService.runnerJob.findUnique + .mockResolvedValueOnce(mockExistingJob) + .mockResolvedValueOnce(mockUpdatedJob); + // updateMany returns count for optimistic locking + mockPrismaService.runnerJob.updateMany.mockResolvedValue({ count: 1 }); const result = await service.cancel(jobId, workspaceId); expect(result).toEqual(mockUpdatedJob); - expect(prisma.runnerJob.update).toHaveBeenCalledWith({ - where: { id: jobId, workspaceId }, + expect(mockPrismaService.runnerJob.updateMany).toHaveBeenCalledWith({ + where: { id: jobId, workspaceId, version: mockExistingJob.version }, data: { status: RunnerJobStatus.CANCELLED, completedAt: expect.any(Date), + version: { increment: 1 }, }, }); }); @@ -405,17 +412,23 @@ describe("RunnerJobsService", () => { id: jobId, workspaceId, status: RunnerJobStatus.QUEUED, + version: 1, }; - mockPrismaService.runnerJob.findUnique.mockResolvedValue(mockExistingJob); - mockPrismaService.runnerJob.update.mockResolvedValue({ + const mockUpdatedJob = { ...mockExistingJob, status: RunnerJobStatus.CANCELLED, - }); + version: 2, + }; + + mockPrismaService.runnerJob.findUnique + .mockResolvedValueOnce(mockExistingJob) + .mockResolvedValueOnce(mockUpdatedJob); + mockPrismaService.runnerJob.updateMany.mockResolvedValue({ count: 1 }); await service.cancel(jobId, workspaceId); - expect(prisma.runnerJob.update).toHaveBeenCalled(); + expect(mockPrismaService.runnerJob.updateMany).toHaveBeenCalled(); }); it("should throw NotFoundException if job not found", async () => { diff --git a/apps/orchestrator/src/git/secret-scanner.service.spec.ts b/apps/orchestrator/src/git/secret-scanner.service.spec.ts index b211c4f..979d022 100644 --- a/apps/orchestrator/src/git/secret-scanner.service.spec.ts +++ b/apps/orchestrator/src/git/secret-scanner.service.spec.ts @@ -434,11 +434,28 @@ SECRET=replace-me // Remove read permissions await fs.chmod(testFile, 0o000); + // Check if we can still read the file (e.g., running as root) + let canReadAsRoot = false; + try { + await fs.readFile(testFile); + canReadAsRoot = true; + } catch { + // Expected behavior for non-root users + } + const result = await service.scanFile(testFile); - expect(result.scannedSuccessfully).toBe(false); - expect(result.scanError).toBeDefined(); - expect(result.hasSecrets).toBe(false); // Not "clean", just unscanned + if (canReadAsRoot) { + // Running as root - file is readable despite chmod 0o000 + // Scanner will successfully scan the file + expect(result.scannedSuccessfully).toBe(true); + expect(result.hasSecrets).toBe(true); // Contains AWS key + } else { + // Normal user - file is unreadable + expect(result.scannedSuccessfully).toBe(false); + expect(result.scanError).toBeDefined(); + expect(result.hasSecrets).toBe(false); // Not "clean", just unscanned + } // Cleanup - restore permissions first await fs.chmod(testFile, 0o644);