Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { NextRequest } from 'next/server'
|
|
import { GET } from '@/app/api/health/route'
|
|
import { prisma } from '@/lib/prisma'
|
|
import { redis } from '@/lib/upload-sessions-redis'
|
|
import { readFileSync } from 'fs'
|
|
|
|
jest.mock('fs', () => ({
|
|
...jest.requireActual('fs'),
|
|
readFileSync: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/prisma', () => ({
|
|
prisma: {
|
|
$queryRaw: jest.fn(),
|
|
},
|
|
}))
|
|
|
|
jest.mock('@/lib/upload-sessions-redis', () => ({
|
|
redis: {
|
|
ping: jest.fn(),
|
|
},
|
|
}))
|
|
|
|
describe('/api/health deployment identity', () => {
|
|
const originalUseRedis = process.env.USE_REDIS
|
|
const originalRedisUrl = process.env.REDIS_URL
|
|
const originalCommit = process.env.DEPLOYMENT_COMMIT
|
|
const bakedCommit = '0123456789abcdef0123456789abcdef01234567'
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
process.env.USE_REDIS = 'true'
|
|
process.env.REDIS_URL = 'redis://unit-test.invalid:6379'
|
|
;(readFileSync as jest.Mock).mockReturnValue(`${bakedCommit}\n`)
|
|
;(prisma.$queryRaw as jest.Mock).mockResolvedValue([{ ok: 1 }])
|
|
;(redis!.ping as jest.Mock).mockResolvedValue('PONG')
|
|
})
|
|
|
|
afterAll(() => {
|
|
if (originalUseRedis === undefined) delete process.env.USE_REDIS
|
|
else process.env.USE_REDIS = originalUseRedis
|
|
if (originalRedisUrl === undefined) delete process.env.REDIS_URL
|
|
else process.env.REDIS_URL = originalRedisUrl
|
|
if (originalCommit === undefined) delete process.env.DEPLOYMENT_COMMIT
|
|
else process.env.DEPLOYMENT_COMMIT = originalCommit
|
|
})
|
|
|
|
test('returns exact deployment commit with healthy database and Redis checks', async () => {
|
|
const response = await GET(new NextRequest('https://example.invalid/api/health'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body).toMatchObject({
|
|
status: 'healthy',
|
|
deploymentCommit: bakedCommit,
|
|
checks: {
|
|
database: { status: 'ok' },
|
|
redis: { status: 'ok' },
|
|
},
|
|
})
|
|
})
|
|
|
|
test('keeps Redis failure visible as degraded so deploy can reject it', async () => {
|
|
;(redis!.ping as jest.Mock).mockRejectedValue(new Error('redis unavailable'))
|
|
|
|
const response = await GET(new NextRequest('https://example.invalid/api/health'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.status).toBe('degraded')
|
|
expect(body.checks.redis.status).toBe('error')
|
|
})
|
|
|
|
test('never trusts a mutable runtime environment variable as image identity', async () => {
|
|
process.env.DEPLOYMENT_COMMIT = 'f'.repeat(40)
|
|
;(readFileSync as jest.Mock).mockReturnValue('not-an-immutable-git-sha')
|
|
|
|
const response = await GET(new NextRequest('https://example.invalid/api/health'))
|
|
const body = await response.json()
|
|
|
|
expect(body.deploymentCommit).toBeNull()
|
|
})
|
|
})
|