quality / commitlint (push) Skipped
quality / changes (push) Failing after 8s
quality / openapi (push) Skipped
quality / web (push) Skipped
quality / api (push) Skipped
CD / quality (push) Failing after 9s
quality / docker-check (push) Skipped
CD / publish (push) Skipped
- genReqId (uuid) + x-request-id в каждом ответе и request_id в error envelope — корреляция ошибок между клиентом и логами - RBAC: /agents/:id/(stats|blocked-ips|blocked-ports) классифицируются как fw:stats:read (reset остаётся под fw:agents:write) - web: test-скрипт + 10 unit-тестов (filter-utils, fleet-kpis, parseClaims, nav) - typecheck-скрипты для api/shared/db; CI: тесты shared и web, typecheck всех пакетов - гигиена: .node-version (22), актуальный .dockerignore, drizzle out → ./migrations, удалены 12 лишних .gitkeep и пустой apps/api/test
111 lines
3.0 KiB
TypeScript
111 lines
3.0 KiB
TypeScript
import { describe, it, expect, afterAll } from 'vitest'
|
|
import { buildApp } from '../app.js'
|
|
import type { AppConfig } from '../config.js'
|
|
|
|
const testConfig: AppConfig = {
|
|
databaseUrl: 'sqlite::memory:',
|
|
jwtSecret: 'test',
|
|
jwtTtlHours: 24,
|
|
serverPort: 8080,
|
|
staticDir: null,
|
|
logLevel: 'error',
|
|
authRequired: false,
|
|
authIssuer: 'https://auth.test',
|
|
authPortalUrl: 'http://localhost:5175',
|
|
publicBaseUrl: 'https://fw.example.com',
|
|
enrollSeed: 'test-seed',
|
|
corsOrigins: [],
|
|
authAuditIngestSecret: null,
|
|
secretKey: null,
|
|
statsRetentionDays: 30,
|
|
}
|
|
|
|
describe('agents CRUD critical paths', () => {
|
|
const appPromise = buildApp({ memory: true, config: testConfig })
|
|
|
|
afterAll(async () => {
|
|
const app = await appPromise
|
|
await app.close()
|
|
})
|
|
|
|
it('creates invite, approves, lists with install curl', async () => {
|
|
const app = await appPromise
|
|
await app.ready()
|
|
|
|
const created = await app.inject({
|
|
method: 'POST',
|
|
url: '/api/v1/install-links',
|
|
payload: { name: 'ops-01', platform: 'linux' },
|
|
})
|
|
expect(created.statusCode).toBe(201)
|
|
const link = created.json() as { agent_id: string }
|
|
|
|
const approve = await app.inject({
|
|
method: 'POST',
|
|
url: `/api/v1/agents/${link.agent_id}/approve`,
|
|
})
|
|
expect(approve.statusCode).toBe(200)
|
|
|
|
const list = await app.inject({ method: 'GET', url: '/api/v1/agents' })
|
|
expect(list.statusCode).toBe(200)
|
|
const items = (list.json() as { items: { id: string; status: string }[] })
|
|
.items
|
|
const agent = items.find((a) => a.id === link.agent_id)
|
|
expect(agent?.status).toBe('approved')
|
|
})
|
|
|
|
it('creates policy set + rule and reorders', async () => {
|
|
const app = await appPromise
|
|
await app.ready()
|
|
|
|
const setRes = await app.inject({
|
|
method: 'POST',
|
|
url: '/api/v1/policy-sets',
|
|
payload: { name: 'test-set' },
|
|
})
|
|
expect(setRes.statusCode).toBe(200)
|
|
const set = setRes.json() as { id: string }
|
|
|
|
const r1 = await app.inject({
|
|
method: 'POST',
|
|
url: '/api/v1/rules',
|
|
payload: {
|
|
set_id: set.id,
|
|
action: 'deny',
|
|
cidr: '1.1.1.1/32',
|
|
},
|
|
})
|
|
expect(r1.statusCode).toBe(200)
|
|
const rule1 = r1.json() as { id: string }
|
|
|
|
const r2 = await app.inject({
|
|
method: 'POST',
|
|
url: '/api/v1/rules',
|
|
payload: {
|
|
set_id: set.id,
|
|
action: 'allow',
|
|
cidr: '8.8.8.8/32',
|
|
},
|
|
})
|
|
expect(r2.statusCode).toBe(200)
|
|
const rule2 = r2.json() as { id: string }
|
|
|
|
const reorder = await app.inject({
|
|
method: 'PUT',
|
|
url: `/api/v1/policy-sets/${set.id}/rules/reorder`,
|
|
payload: {
|
|
ordered_ids: [rule2.id, rule1.id],
|
|
},
|
|
})
|
|
expect(reorder.statusCode).toBe(200)
|
|
|
|
const rules = await app.inject({
|
|
method: 'GET',
|
|
url: `/api/v1/policy-sets/${set.id}/rules`,
|
|
})
|
|
expect(rules.statusCode).toBe(200)
|
|
const items = (rules.json() as { items: { id: string }[] }).items
|
|
expect(items[0]?.id).toBe(rule2.id)
|
|
})
|
|
})
|