fix(api): fail-safe прод-старт, транзакции и санитизация install-скриптов

- прод-режим отказывается стартовать без AUTH_REQUIRED и реальных секретов
  (opt-out через EVOFW_ALLOW_UNSAFE)
- CORS: whitelist через CORS_ORIGINS вместо origin:true; CSP для раздаваемого SPA
- транзакции для setAgentPolicySets, reorderPolicyRules, replaceResolvedForRule,
  replaceIpListEntries
- install-скрипты: Zod-валидация имени ссылки, экранирование $ и контрольных
  символов в RouterOS-рендере
- constant-time сравнение enroll-seed
- опциональное шифрование токена EvoBGP в БД (EVOFW_SECRET_KEY, AES-256-GCM)
  и маскирование per-list api_token в ответах
- graceful shutdown (SIGTERM/SIGINT) + тесты
This commit is contained in:
Denozordec
2026-09-20 18:51:47 +07:00
parent 45812fef6a
commit 40030ce06c
23 changed files with 493 additions and 69 deletions
+4 -3
View File
@@ -15,6 +15,7 @@ import {
} from '../services/lists/entries.js'
import type { AppConfig } from '../config.js'
import { auditMutation } from '../services/audit.js'
import { maskListConfig, sealListConfig } from '../services/secret-cipher.js'
export const listsRoutes: FastifyPluginAsync<{ config: AppConfig }> = async (
app,
@@ -32,7 +33,7 @@ export const listsRoutes: FastifyPluginAsync<{ config: AppConfig }> = async (
id: l.id,
name: l.name,
type: l.type,
config_json: l.configJson,
config_json: maskListConfig(l.configJson),
content_hash: l.contentHash,
refreshed_at: l.refreshedAt,
last_error: l.lastError,
@@ -52,7 +53,7 @@ export const listsRoutes: FastifyPluginAsync<{ config: AppConfig }> = async (
id,
name: body.name,
type,
configJson: JSON.stringify(body.config ?? {}),
configJson: sealListConfig({ ...(body.config ?? {}) }),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
})
@@ -81,7 +82,7 @@ export const listsRoutes: FastifyPluginAsync<{ config: AppConfig }> = async (
id: list!.id,
name: list!.name,
type: list!.type,
config_json: list!.configJson,
config_json: maskListConfig(list!.configJson),
created_at: list!.createdAt,
updated_at: list!.updatedAt,
}