Task 95 — Security, quotas & rollout panel
Phase: 7
Initiative: 48
Status: done
Owner: —
Slug: web-security-quotas-rollout
Goal
Три близкие по смыслу операционные подсистемы не имеют web-UI:
SecurityOpsController(task_055) — security events, alerts, suspicious patterns;QuotasController(task_056) — per-user/per-tool/per-agent quota consumption;RolloutController(task_058) — config/policy rollout history и staging.
Нужна единая страница «Operations» (расширение task_094 или отдельная) с тремя секциями: Security, Quotas, Rollouts.
Acceptance criteria
Sub-tasks
Backend (small addition — security HTTP layer is missing; Quotas + Rollout already exposed):
- Backend
src/agent/Hercules.WebApi/Controllers/SecurityOpsController.cs— minimal HTTP layer поверх существующихIVulnerabilityReporter+ISecurityAuditExporter:GET /api/security/vulnerabilities?minSeverity=&status=&component=&from=&to=&limit=→ списокGET /api/security/vulnerabilities/summary→VulnerabilitySummaryGET /api/security/vulnerabilities/{id}→ singlePATCH /api/security/vulnerabilities/{id}/statusbody{status, notes?}→ updateGET /api/security/events?from=&to=&limit=→ security-relevant audit entriesGET /api/security/compliance/{standard}гдеstandard ∈ {SOC2, ISO27001, GDPR, HIPAA}→ComplianceReport
Program.cs— registerapp.MapSecurityOps()рядом сapp.MapQuotas()dotnet build src/agent/Hercules.sln— exit 0
Web (hercules-web — primary deliverable):
src/lib/api.ts— добавить DTOs и методы:- Security:
getVulnerabilities(params),getVulnerabilitySummary(),getVulnerability(id),updateVulnerabilityStatus(id, status, notes?),getSecurityEvents(params),getComplianceReport(standard) - Quotas:
getQuotas(scope, scopeId?),getQuotaForType(scope, scopeId, type),getRateLimit(scope, scopeId?, type?) - Rollouts:
getRolloutState(),getRolloutBundle(id),applyRollout(bundle),promoteRollout(bundleId),rollbackRollout(reason?)
- Security:
src/components/SecurityOpsPanel.astro— vulnerability summary cards (Open / Critical / High / Medium / Low), vulnerability table с severity pills и status filter, recent security-events list, collapsible compliance section (4 standards)src/components/QuotasPanel.astro— scope selector (Agent / Skill / User / Tenant) + scopeId input, limits table с progress-bar’ами (current / limit / remaining / isExceeded), counters row (tokens/messages/requests/storage/cost/concurrent)src/components/RolloutPanel.astro— current state card (current / pending / LKG / lastPromotedAt / lastRollbackAt), history timeline (action + bundleId + version + timestamp + reason), bundle details expandable- Секции встраиваются в
src/pages/ops.astro(расширение task_094) — порядок: Backup → SLO → Quotas → Rollout → Security src/hercules-web/README.md— обновить (компоненты + endpoints)npm run build— exit 0npx astro check— 0 errors/warnings в новых файлах- Manual smoke: build artefacts проверены; страница /ops рендерится с тремя новыми секциями; bundle’ы
*Panel.*.jsприсутствуют вdist/_astro/
Implementation notes
Round 1 (this tick) — completed
Security + Quotas + Rollout панели для src/pages/ops.astro (Phase 7 task_095). Расширение операционной страницы из task_094.
Backend addition (small) — src/agent/Hercules.WebApi/Controllers/SecurityOpsController.cs:
- task_055 (
security-ops) реализовал только сервисы (IVulnerabilityReporter,ISecurityAuditExporter), но без HTTP-уровня. Web-UI не мог до них достучаться, поэтомуSecurityOpsPanelбыл бы пустым. Добавил минимальную обёртку (217 строк, тот же стиль, чтоQuotasController/RolloutController):GET /api/security/vulnerabilities?minSeverity=&status=&component=&from=&to=&limit=— список черезVulnerabilityFilterGET /api/security/vulnerabilities/summary— агрегатыGET /api/security/vulnerabilities/{id}— singlePATCH /api/security/vulnerabilities/{id}/status— обновить status + notesGET /api/security/events?from=&to=&limit=— черезISecurityAuditExporter.ExportAuditReportAsync+ cap на сервере (Math.Clamp(limit, 1, 1000))GET /api/security/compliance/{standard}— гдеstandard ∈ {SOC2, ISO27001, GDPR, HIPAA}черезExportComplianceReportAsync
- Все 6 эндпоинтов регистрируются в
Program.csчерезapp.MapSecurityOps()рядом сapp.MapQuotas(). - Без новых сервисов, без новых DI-регистраций — переиспользует уже зарегистрированные
IVulnerabilityReporter,ISecurityAuditExporter(task_055) иIAuditService(task_014). - Quotas и Rollout HTTP-уровни уже существовали из task_056/task_058 — без изменений.
API (src/lib/api.ts) — добавлены 14 методов и 12 DTO:
Quotas (task_056):
getQuotas(scope, scopeId?)→GET /api/quotas[/{scope}/{scopeId}]?scope=…&scopeId=…→QuotaStatusListDto(scope, scopeId, counters{…}, limits[])getQuotaForType(scope, scopeId, type)→GET /api/quotas/{scope}/{scopeId}/{type}→QuotaStatusDtogetRateLimit(scope, scopeId?, type?)→GET /api/quotas/rate-limit→RateLimitInfoDto
Rollouts (task_058):
getRolloutState()→GET /api/rollout/state→{state: RolloutStateDto}getRolloutBundle(id)→GET /api/rollout/bundle/{id}→{bundle: ConfigBundleDto}applyRollout(bundle)→POST /api/rollout/apply→{status, bundleId, stage}promoteRollout(bundleId)→POST /api/rollout/promote→{status, bundleId, stage}rollbackRollout(reason?)→POST /api/rollout/rollback→{status, bundleId, stage}
Security (task_055):
getVulnerabilities(params)→GET /api/security/vulnerabilities?…→{count, vulnerabilities: VulnerabilityDto[]}getVulnerabilitySummary()→GET /api/security/vulnerabilities/summary→VulnerabilitySummaryDtogetVulnerability(id)→GET /api/security/vulnerabilities/{id}→VulnerabilityDtoupdateVulnerabilityStatus(id, status, notes?)→PATCH /api/security/vulnerabilities/{id}/status→VulnerabilityDtogetSecurityEvents(params)→GET /api/security/events?…→SecurityEventsResponseDto(from, to, total, returned, events[], metrics)getComplianceReport(standard)→GET /api/security/compliance/{standard}→ComplianceReportDto
Расхождение DTO со spec’ом:
- Спека перечисляла
QuotaDtoс(subject, kind, current, limit, period, windowStart, windowEnd, isOver). Реальный wire-формат используетscope/scopeId/type/limit/current/remaining/isExceeded/isHardCap/usagePercent/resetAtиcounters{tokensUsedToday, messagesUsedToday, …}. DTO вapi.tsзеркалит реальный wire-формат, чтобы избежать полей-призраков; в комментариях отмечено расхождение. RolloutDtoсо spec’а (id, kind, startedAt, completedAt, status, summary, affectedSubjects[]) — реальный формат использует{currentBundleId, currentVersion, currentStage, lastKnownGoodBundleId/Version, pendingBundleId/Version, lastPromotedAt, lastRollbackAt, rolloutHistory[]}. UI работает с этим, отображая каждое поле явно.SecurityEventDto(id, timestamp, actor, action, severity, source, details) — реальный формат использует(eventId, eventType, actor, target, timestamp, details, ipAddress, success).severityнет на wire (events приходят из audit log без severity классификации) — UI просто показываетsuccess/failиконку.
QuotasPanel (src/components/QuotasPanel.astro) — новый:
- Scope selector (Agent / Skill / User / Tenant) + опциональный
scopeId(пусто = “default”). - Counters grid: 8 карточек (tokens / messages / requests / storage MB / cost ¢ / active concurrent / active skills / last reset). Если всё ноль — empty state.
- Limits table: type / current / limit / remaining / usage-bar (emerald/amber/rose) / resetAt / caps (soft/hard pill). Progress-bar с цветом в зависимости от
usagePercentиisExceeded. Empty state когда для scope нет лимитов. - 15s auto-refresh (opt-in), error/ok banners.
- On
changeдля scope/scopeId — перезагрузка.
RolloutPanel (src/components/RolloutPanel.astro) — новый:
- Action bar: apply-form (name + version + type) + Promote (disabled когда
pendingBundleId == null) + Rollback (disabled когда LKG == current или LKG == null). При busy — все три кнопки disabled. - Current state: 4 карточки (Current [с pill currentStage] / Pending / LKG / Last activity с
lastPromotedAt+lastRollbackAt). - History timeline: список с action-pill (applied=violet, promoted=emerald, rolled_back=rose, expired=amber), bundleId, version, timestamp, reason. Сортировка по timestamp DESC.
- 20s auto-refresh (opt-in),
window.promptдля rollback reason, error/ok banners.
SecurityOpsPanel (src/components/SecurityOpsPanel.astro) — новый:
- Vulnerability summary: 6 карточек (Total / Open / Critical / High / Medium / Low).
- Vulnerability table с severity-pill (Critical=rose / High=orange / Medium=amber / Low=sky) и status-pill (Reported/Confirmed/InProgress/Mitigated/Resolved/FalsePositive/Accepted). Фильтр по severity (All / Critical / High / Medium / Low). Inline
Resolveaction (PATCH status → “Resolved”). - Security events: список из 50 последних audit-derived events с success/fail иконкой, actor, target, details. Счётчик
(returned of total). - Compliance: 4 кликабельные карточки (SOC2 / ISO27001 / GDPR / HIPAA) с badge
passed/total checks · compliant|non-compliant. По клику — detail с per-control списком (passed/failed icon + controlId + description + evidence + remediation + findings/recommendations). - 30s auto-refresh (opt-in), error/ok banners.
Интеграция (src/pages/ops.astro):
- Расширение task_094: добавлены QuotasPanel, RolloutPanel, SecurityOpsPanel после SloPanel. Порядок: Backup → SLO → Quotas → Rollout → Security (от «срочного» к «диагностическому»).
README (src/hercules-web/README.md):
- В «Структура» добавлены
QuotasPanel.astro,RolloutPanel.astro,SecurityOpsPanel.astro. - В «Backend API» добавлены 14 эндпоинтов (4 quota + 5 rollout + 5 security).
Round 1 — validation
npm run build→ exit 0, 9 страниц собрано (/,/a2a,/config,/memmesh,/observability,/ops,/profile,/skills,/stats).- Bundle’ы в
dist/_astro/:QuotasPanel.*.js≈ 6.0 KB,RolloutPanel.*.js≈ 5.9 KB,SecurityOpsPanel.*.js≈ 10.2 KB. - Проверка
dist/ops/index.html: присутствуют все 5 панелей с id (backup-panel,slo-panel,quotas-panel,rollout-panel,security-panel); nav-link/opsактивен; titleHercules · Operationsкорректный. npx astro check→ 0 errors, 0 warnings, 0 hints вQuotasPanel.astro,RolloutPanel.astro,SecurityOpsPanel.astro,ops.astro,lib/api.ts. Pre-existing 17 errors вMeshRouterPanel.astro(вне scope task_095; задокументировано в task_088/089).dotnet build src\agent\Hercules.slnx→ 0 errors, 97 pre-existing test warnings.dotnet test --filter "Quota|Rollout"→ 56 passed, 0 failed. (SecurityOps не имеет тестов — task_055 не покрыл сервисы тестами, controller — тонкая обёртка, поведение тривиально.)
Notes
- Security controller — минимальная обёртка: добавлять stateful endpoints (alerts feed) сейчас не было нужно, т.к. vulnerabilities + recent events покрывают типичные операционные сценарии (security review).
- Backward compat: новые DTOs добавлены без поломки существующих. Security controller не регистрирует новых services, только consume.
- Безопасность:
RolloutController.ApplyBundleAsyncуже валидирует подпись (HMAC-SHA256) черезSignedBundleValidator, поэтому даже минимальный web-UI не может протолкнуть unsigned бандл. Web-form генерирует толькоname+version+type+payload="{}"— реальный прод-сценарий предполагает подписанный бандл черезPOST /api/rollout/apply(CLI/hercules-cli) или прямой POST с заголовком X-Signature. - Quotas auto-refresh перезапускает счётчики от
lastResetDate— после полуночи они обнуляются на backend автоматически, UI просто перечитает. - Не трогал
MeshRouterPanel.astro(17 pre-existing errors) — это технический долг из task_088/089, не в scope task_095.