Files
EvoFirewall/apps/api/src/services/evobgp.ts
T
Denozordec 9fa6269174
quality / changes (push) Successful in 7s
quality / commitlint (push) Skipped
quality / openapi (push) Successful in 30s
quality / web (push) Successful in 1m3s
quality / api (push) Successful in 1m15s
quality / linux-agent-smoke (push) Failing after 27s
quality / docker-check (push) Failing after 2m28s
CD / quality (push) Failing after 5m52s
CD / publish (push) Skipped
feat: harden firewall policies telemetry and operations
Implement reliable agent apply, telemetry v2, analytics retention, guarded rollouts, enrollment, labels and webhooks. Improve ReUI frontend data safety and bounded list loading, and add Docker smoke, recovery and resource checks. Document local verification and pending native acceptance.
2026-10-26 13:10:58 +07:00

42 lines
2.3 KiB
TypeScript

import { safeFetchJson, SOURCE_LIMITS } from './safe-fetch.js'
/** Fully collect bounded cursor pages. Never accept an incomplete snapshot. */
export async function fetchEvobgpPages(base: string, token: string, path: string, limit: number): Promise<Record<string, unknown>[]> {
const pages: Record<string, unknown>[] = []
const seen = new Set<string>()
let cursor: string | undefined
let elements = 0
let bytes = 0
const deadline = Date.now() + SOURCE_LIMITS.timeoutMs
for (let page = 0; page < SOURCE_LIMITS.pages; page++) {
if (Date.now() >= deadline) throw new Error('EvoBGP snapshot deadline exceeded')
if (bytes >= SOURCE_LIMITS.totalBytes) throw new Error('EvoBGP snapshot byte limit exceeded')
const url = new URL(`${base.replace(/\/$/, '')}${path}`)
url.searchParams.set('limit', String(limit))
if (cursor) url.searchParams.set('cursor', cursor)
const response = await safeFetchJson(url, {
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
timeoutMs: deadline - Date.now(),
maxBytes: Math.min(SOURCE_LIMITS.bytes, SOURCE_LIMITS.totalBytes - bytes),
})
const data = response.data
bytes += response.bytes
if (bytes > SOURCE_LIMITS.totalBytes) throw new Error('EvoBGP snapshot byte limit exceeded')
if (!data || typeof data !== 'object' || Array.isArray(data)) throw new Error('Invalid EvoBGP page')
const body = data as Record<string, unknown>
const items = body.prefixes ?? body.items
if (!Array.isArray(items)) throw new Error('Invalid EvoBGP page items')
elements += items.length
if (elements > SOURCE_LIMITS.elements) throw new Error('EvoBGP snapshot element limit exceeded')
if (body.has_more !== undefined && typeof body.has_more !== 'boolean') throw new Error('Invalid EvoBGP has_more')
if (body.next_cursor !== undefined && body.next_cursor !== null && (typeof body.next_cursor !== 'string' || body.next_cursor.length > 2048)) throw new Error('Invalid EvoBGP next_cursor')
pages.push(body)
if (body.has_more !== true && !body.next_cursor) return pages
const next = body.next_cursor
if (typeof next !== 'string' || !next || seen.has(next)) throw new Error('Incomplete or repeated EvoBGP cursor')
seen.add(next)
cursor = next
}
throw new Error('EvoBGP page limit exceeded')
}