chore(ci): request-id, RBAC stats, web-тесты и гигиена CI
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
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
This commit is contained in:
@@ -2,7 +2,9 @@ import { defineConfig } from 'drizzle-kit'
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/schema.ts',
|
||||
out: './drizzle',
|
||||
// Migration SQL files live here and are applied by the custom runner in
|
||||
// src/client.ts (runMigrations); drizzle-kit generate adds new files to it.
|
||||
out: './migrations',
|
||||
dialect: 'sqlite',
|
||||
dbCredentials: { url: 'data/app.db' },
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "tsup src/index.ts --format esm --dts",
|
||||
"dev": "tsup src/index.ts --format esm --dts --watch",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "tsup src/index.ts --format esm --dts",
|
||||
"dev": "tsup src/index.ts --format esm --dts --watch",
|
||||
"test": "vitest run --passWithNoTests"
|
||||
|
||||
@@ -11,6 +11,20 @@ describe('permissionForRequest', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('maps agent stats endpoints to stats permission, not agents', () => {
|
||||
expect(
|
||||
permissionForRequest('GET', '/api/v1/agents/a1/stats'),
|
||||
).toBe('fw:stats:read')
|
||||
expect(
|
||||
permissionForRequest('GET', '/api/v1/agents/a1/blocked-ips'),
|
||||
).toBe('fw:stats:read')
|
||||
// reset is destructive — stays under agents write
|
||||
expect(
|
||||
permissionForRequest('POST', '/api/v1/agents/a1/stats/reset'),
|
||||
).toBe('fw:agents:write')
|
||||
expect(permissionForRequest('GET', '/api/v1/agents')).toBe('fw:agents:read')
|
||||
})
|
||||
|
||||
it('maps integrations to lists read / settings admin', () => {
|
||||
expect(
|
||||
permissionForRequest('GET', '/api/v1/integrations/evobgp/communities'),
|
||||
|
||||
@@ -29,6 +29,12 @@ export function permissionForRequest(
|
||||
const m = method.toUpperCase()
|
||||
const write = m !== 'GET' && m !== 'HEAD' && m !== 'OPTIONS'
|
||||
|
||||
// Agent statistics live under /agents/:id/… — classify as stats, not agents.
|
||||
if (
|
||||
/^\/api\/v1\/agents\/[^/]+\/(stats|blocked-ips|blocked-ports)$/.test(path)
|
||||
) {
|
||||
return 'fw:stats:read'
|
||||
}
|
||||
if (path.startsWith('/api/v1/agents') || path.startsWith('/api/v1/install-links')) {
|
||||
return write ? 'fw:agents:write' : 'fw:agents:read'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user