feat(api, web): enhance agent management and linting capabilities
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 2m17s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped

- Added a new linting command for OpenAPI specifications in the package.json, improving code quality checks.
- Updated frontend documentation to clarify component usage and structure, including detailed descriptions for `SettingsShell` and `Auth callback`.
- Refactored agent-related API routes to streamline control-plane functionalities, consolidating multiple routes for better organization.
- Improved error handling in the API to provide more informative responses for validation errors, enhancing user feedback during interactions.

These changes enhance the overall development experience and improve the management of agents within the application.
This commit is contained in:
Denozordec
2026-07-30 14:13:05 +07:00
parent fb95ef22b3
commit f160992d94
68 changed files with 3155 additions and 6899 deletions
+103
View File
@@ -0,0 +1,103 @@
import type { FastifyPluginAsync } from 'fastify'
import { repos } from '@evofw/db'
import {
createPolicySetBodySchema,
patchPolicySetBodySchema,
} from '@evofw/shared'
import { AppError } from '../plugins/error-handler.js'
import type { AppConfig } from '../config.js'
import { auditMutation } from '../services/audit.js'
import { mapPolicySet, mapPolicySets } from '../services/row-mappers.js'
export const policySetsRoutes: FastifyPluginAsync<{ config: AppConfig }> = async (
app,
opts,
) => {
const { config } = opts
app.get('/policy-sets', async () => ({
items: mapPolicySets(app.db, repos.listPolicySets(app.db)),
}))
app.get<{ Params: { id: string } }>('/policy-sets/:id', async (req) => {
const s = repos.getPolicySet(app.db, req.params.id)
if (!s) throw new AppError('NOT_FOUND', 'Policy set not found', 404)
return {
...mapPolicySet(s, app.db),
agent_ids: repos.listAgentIdsForSet(app.db, s.id),
}
})
app.post('/policy-sets', async (req) => {
const body = createPolicySetBodySchema.parse(req.body)
const row = repos.insertPolicySet(app.db, {
id: crypto.randomUUID(),
name: body.name.trim(),
description: body.description ?? null,
enabled: body.enabled === false ? 0 : 1,
policyMode: 'blacklist',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
})
auditMutation(app, config, req, {
action: 'policy_set.create',
targetType: 'app_resource',
targetId: row!.id,
summary: `Создан набор политик: ${row!.name}`,
details: { set_id: row!.id },
})
return mapPolicySet(row!, app.db)
})
app.patch<{ Params: { id: string } }>('/policy-sets/:id', async (req) => {
const body = patchPolicySetBodySchema.parse(req.body)
const s = repos.getPolicySet(app.db, req.params.id)
if (!s) throw new AppError('NOT_FOUND', 'Policy set not found', 404)
const updated = repos.updatePolicySet(app.db, s.id, {
name: body.name?.trim(),
description: body.description,
enabled: body.enabled === undefined ? undefined : body.enabled ? 1 : 0,
})
if (body.enabled !== undefined) {
repos.bumpAgentsForSet(app.db, s.id)
}
auditMutation(app, config, req, {
action: 'policy_set.update',
targetType: 'app_resource',
targetId: s.id,
summary: `Обновлён набор политик: ${updated!.name}`,
details: {
set_id: s.id,
enabled: body.enabled,
name: body.name,
},
})
return mapPolicySet(updated!, app.db)
})
app.delete<{ Params: { id: string } }>('/policy-sets/:id', async (req) => {
const s = repos.getPolicySet(app.db, req.params.id)
try {
const agentIds = repos.listAgentIdsForSet(app.db, req.params.id)
repos.deletePolicySet(app.db, req.params.id)
for (const id of agentIds) repos.bumpAgentGeneration(app.db, id)
if (s) {
auditMutation(app, config, req, {
action: 'policy_set.delete',
severity: 'warning',
targetType: 'app_resource',
targetId: s.id,
summary: `Набор политик удалён: ${s.name}`,
details: { set_id: s.id, agents_affected: agentIds.length },
})
}
} catch (err) {
throw new AppError(
'VALIDATION_ERROR',
err instanceof Error ? err.message : String(err),
400,
)
}
return { ok: true }
})
}