ops: remediate deployment drift
This commit is contained in:
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
Дата проверки: 2026-06-07.
|
Дата проверки: 2026-06-07.
|
||||||
|
|
||||||
Статус: рабочий внутренний pilot-контур подтвержден частично. Контур собирает и
|
Статус после TASK_014: рабочий внутренний pilot-контур приведен к Demo Freeze
|
||||||
показывает реальные данные, но перед расширением пилота нужно закрыть
|
v1 по portal runtime, production-hardening endpoints и основным live smoke.
|
||||||
deployment/version drift между Demo Freeze v1 и фактически запущенным portal
|
Контур собирает и показывает реальные данные; расширение пилота допустимо
|
||||||
runtime.
|
только контролируемо, после ручной проверки UEBA evidence и назначения
|
||||||
|
операционного ownership.
|
||||||
|
|
||||||
## Executive Summary
|
## Executive Summary
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ runtime.
|
|||||||
- Forensics view и базовые portal tabs открываются;
|
- Forensics view и базовые portal tabs открываются;
|
||||||
- Windows runtime содержит активный текущий агентский процесс и watcher-процессы.
|
- Windows runtime содержит активный текущий агентский процесс и watcher-процессы.
|
||||||
|
|
||||||
Ключевые gaps:
|
Ключевые gaps, найденные до TASK_014:
|
||||||
|
|
||||||
- фактический portal runtime отстает от Demo Freeze v1: отдельные endpoints
|
- фактический portal runtime отстает от Demo Freeze v1: отдельные endpoints
|
||||||
`/portal/api/workforce/kpi/explain`, `/portal/api/risk/narrative` и
|
`/portal/api/workforce/kpi/explain`, `/portal/api/risk/narrative` и
|
||||||
@@ -39,9 +40,21 @@ runtime.
|
|||||||
- UEBA на live-контуре возвращает `critical` score; нужна ручная проверка
|
- UEBA на live-контуре возвращает `critical` score; нужна ручная проверка
|
||||||
evidence, чтобы отличить реальный риск от шумного правила.
|
evidence, чтобы отличить реальный риск от шумного правила.
|
||||||
|
|
||||||
Вывод: контур можно использовать для ограниченного внутреннего просмотра
|
TASK_014 remediation update:
|
||||||
реальных данных и сбора обратной связи, но не стоит расширять пилот до
|
|
||||||
10-50 пользователей, пока не закрыт deployment/version drift.
|
- deployment/version drift закрыт controlled deploy актуального release binary;
|
||||||
|
- live `/healthz`, `/readyz`, `/version`, `/metrics` теперь отвечают `200`;
|
||||||
|
- request id / correlation id headers возвращаются;
|
||||||
|
- live Explainable KPI, Risk Narrative и Executive Action Center endpoints
|
||||||
|
отвечают `200`;
|
||||||
|
- live production hardening smoke прошел;
|
||||||
|
- live browser conformance smoke прошел;
|
||||||
|
- live portal tabs smoke прошел.
|
||||||
|
|
||||||
|
Вывод: контур можно использовать для контролируемого внутреннего pilot review и
|
||||||
|
подготовки ограниченного пилота. Перед расширением на 10-50 пользователей
|
||||||
|
остается вручную разобрать UEBA `critical` evidence и закрепить порядок
|
||||||
|
операционной поддержки.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
@@ -90,37 +103,38 @@ runtime.
|
|||||||
| Gateway `/portal/` | `401` снаружи | Внешний доступ закрыт авторизацией |
|
| Gateway `/portal/` | `401` снаружи | Внешний доступ закрыт авторизацией |
|
||||||
| Portal local `/portal/` | `200` | UI доступен на gateway host |
|
| Portal local `/portal/` | `200` | UI доступен на gateway host |
|
||||||
| Portal local `/portal/api/health` | `200` | API health доступен |
|
| Portal local `/portal/api/health` | `200` | API health доступен |
|
||||||
| Portal local `/healthz` | `404` | Production-hardening endpoint не доступен на live runtime |
|
| Portal local `/healthz` | `200` | Production-hardening endpoint подтвержден после TASK_014 |
|
||||||
| Portal local `/readyz` | `404` | Production-hardening endpoint не доступен на live runtime |
|
| Portal local `/readyz` | `200` | Production-hardening endpoint подтвержден после TASK_014 |
|
||||||
| Portal local `/version` | `404` | Production-hardening endpoint не доступен на live runtime |
|
| Portal local `/version` | `200` | Production-hardening endpoint подтвержден после TASK_014 |
|
||||||
| Portal local `/metrics` | `404` | Production-hardening endpoint не доступен на live runtime |
|
| Portal local `/metrics` | `200` | Prometheus text metrics подтверждены после TASK_014 |
|
||||||
| ActivityWatch `/api/0/settings` | `200` | AW API отвечает |
|
| ActivityWatch `/api/0/settings` | `200` | AW API отвечает |
|
||||||
|
|
||||||
Request/correlation headers:
|
Request/correlation headers после TASK_014:
|
||||||
|
|
||||||
- `X-Request-Id`: не возвращается live portal API;
|
- `X-Request-Id`: возвращается live portal API;
|
||||||
- `X-Correlation-Id`: не возвращается live portal API.
|
- `X-Correlation-Id`: возвращается live portal API.
|
||||||
|
|
||||||
Metrics:
|
Metrics:
|
||||||
|
|
||||||
- Prometheus metrics format на фактическом portal runtime не подтвержден,
|
- Prometheus metrics format на фактическом portal runtime подтвержден через
|
||||||
потому что `/metrics` возвращает `404`.
|
`/metrics`.
|
||||||
|
|
||||||
## Portal Validation
|
## Portal Validation
|
||||||
|
|
||||||
Проверено через tunnel к фактическому gateway-local portal port. Screenshots
|
Проверено через tunnel к фактическому gateway-local portal port. Screenshots
|
||||||
создавались только во временном каталоге вне репозитория и не коммитились.
|
создавались только во временном каталоге вне репозитория и не коммитились.
|
||||||
|
|
||||||
Результат `scripts/browser-conformance-smoke.mjs` на live-контуре:
|
Результат `scripts/browser-conformance-smoke.mjs` на live-контуре после
|
||||||
|
TASK_014:
|
||||||
|
|
||||||
| View | Результат | Комментарий |
|
| View | Результат | Комментарий |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Executive | FAIL | Не найдены Pilot v1 blocks: KPI, Explainable KPI, Risk Narrative, Recommended Actions |
|
| Executive | OK | KPI, Explainable KPI, Risk Narrative и Recommended Actions отображаются |
|
||||||
| Workforce | FAIL | Не найдены ожидаемые freeze-маркеры KPI/Trend/Explainability |
|
| Workforce | OK | KPI, подразделения, тренды и explainability отображаются |
|
||||||
| Security | FAIL | Не найдены ожидаемые freeze-маркеры security/risk/action blocks |
|
| Security | OK | Security actions, events, correlation и candidates отображаются |
|
||||||
| Forensics | OK | Расследования, timeline, материалы и аудит отображаются |
|
| Forensics | OK | Расследования, timeline, материалы и аудит отображаются |
|
||||||
|
|
||||||
Результат `scripts/detmir-portal-tabs-smoke.mjs` на live-контуре:
|
Результат `scripts/detmir-portal-tabs-smoke.mjs` на live-контуре после TASK_014:
|
||||||
|
|
||||||
- базовые tabs открываются;
|
- базовые tabs открываются;
|
||||||
- loading status доходит до ready;
|
- loading status доходит до ready;
|
||||||
@@ -128,7 +142,7 @@ Metrics:
|
|||||||
- Security events доступны;
|
- Security events доступны;
|
||||||
- manager/security/forensics/admin view checks проходят;
|
- manager/security/forensics/admin view checks проходят;
|
||||||
- server role gates проходят;
|
- server role gates проходят;
|
||||||
- Executive dashboard layer и expected management block order не проходят.
|
- Executive dashboard layer и expected management block order проходят.
|
||||||
|
|
||||||
## KPI Validation
|
## KPI Validation
|
||||||
|
|
||||||
@@ -159,22 +173,17 @@ Metrics:
|
|||||||
|
|
||||||
## Explainable KPI Validation
|
## Explainable KPI Validation
|
||||||
|
|
||||||
Live endpoint:
|
Live endpoint после TASK_014:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/portal/api/workforce/kpi/explain -> 404
|
/portal/api/workforce/kpi/explain -> 200
|
||||||
```
|
```
|
||||||
|
|
||||||
Вывод:
|
Вывод:
|
||||||
|
|
||||||
- Explainable KPI реализован и покрыт тестами в текущей кодовой базе;
|
- Explainable KPI развернут на рабочем контуре;
|
||||||
- на рабочем контуре отдельный endpoint не развернут;
|
- live UI показывает ожидаемый блок `Почему такой индекс активности?`;
|
||||||
- live UI не показывает ожидаемый блок `Почему такой индекс активности?` в
|
- прежний `404` был следствием устаревшего deployed binary.
|
||||||
соответствии с freeze smoke.
|
|
||||||
|
|
||||||
Gap:
|
|
||||||
|
|
||||||
- deployment/version drift между текущим repository state и live portal runtime.
|
|
||||||
|
|
||||||
## UEBA Validation
|
## UEBA Validation
|
||||||
|
|
||||||
@@ -203,35 +212,33 @@ Live endpoint:
|
|||||||
|
|
||||||
## Risk Narrative Validation
|
## Risk Narrative Validation
|
||||||
|
|
||||||
Live endpoint:
|
Live endpoint после TASK_014:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/portal/api/risk/narrative -> 404
|
/portal/api/risk/narrative -> 200
|
||||||
```
|
```
|
||||||
|
|
||||||
Вывод:
|
Вывод:
|
||||||
|
|
||||||
- Risk Narrative реализован в текущей кодовой базе и задокументирован в
|
- Risk Narrative развернут на рабочем контуре;
|
||||||
`docs/RISK_NARRATIVE_RU.md`;
|
- Executive UI block соответствует Demo Freeze v1 ожиданиям;
|
||||||
- на рабочем контуре отдельный endpoint и Executive UI block не соответствуют
|
- Risk Narrative можно показывать как deployed capability, сохраняя честное
|
||||||
Demo Freeze v1 ожиданиям;
|
ограничение: это rule-based объяснение, не ML-прогноз.
|
||||||
- risk narrative нельзя демонстрировать на live-контуре как подтвержденный
|
|
||||||
deployed capability до обновления runtime.
|
|
||||||
|
|
||||||
## Executive Action Center Validation
|
## Executive Action Center Validation
|
||||||
|
|
||||||
Live endpoint:
|
Live endpoint после TASK_014:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/portal/api/actions -> 404
|
/portal/api/actions -> 200
|
||||||
```
|
```
|
||||||
|
|
||||||
Вывод:
|
Вывод:
|
||||||
|
|
||||||
- Executive Action Center реализован в текущей кодовой базе и задокументирован;
|
- Executive Action Center развернут на рабочем контуре;
|
||||||
- live runtime не отдает отдельный actions endpoint;
|
- live runtime отдает отдельный actions endpoint;
|
||||||
- рекомендации в demo/freeze сценарии нельзя заявлять как live-deployed feature
|
- рекомендации можно показывать как deployed rule-based guidance, без claims об
|
||||||
до обновления portal runtime.
|
автоматическом remediation.
|
||||||
|
|
||||||
## Agent/Data Flow Validation
|
## Agent/Data Flow Validation
|
||||||
|
|
||||||
@@ -311,18 +318,15 @@ Backlog/dead-letter:
|
|||||||
|
|
||||||
## Documentation Mismatches
|
## Documentation Mismatches
|
||||||
|
|
||||||
Найдены важные расхождения:
|
Расхождения, найденные TASK_013, закрыты TASK_014:
|
||||||
|
|
||||||
1. Документация Demo Freeze v1 описывает production-hardening endpoints
|
1. Production-hardening endpoints `/healthz`, `/readyz`, `/version`,
|
||||||
`/healthz`, `/readyz`, `/version`, `/metrics`; live portal runtime их не
|
`/metrics` теперь доступны на фактическом portal port.
|
||||||
отдает на фактическом portal port.
|
2. Standalone endpoints `/api/workforce/kpi/explain`,
|
||||||
2. Документация и текущая кодовая база описывают standalone endpoints
|
`/api/risk/narrative`, `/api/actions` теперь доступны на live runtime.
|
||||||
`/api/workforce/kpi/explain`, `/api/risk/narrative`, `/api/actions`; live
|
3. Visual smoke текущей freeze-ветки проходит Executive, Workforce, Security и
|
||||||
portal runtime на gateway-local path возвращает `404`.
|
Forensics views.
|
||||||
3. Visual smoke текущей freeze-ветки ожидает Executive blocks, которых нет в
|
4. Live runtime обновлен controlled deploy актуального release binary.
|
||||||
live runtime.
|
|
||||||
4. Public naming hygiene в repository docs закрыт, но live runtime/report text
|
|
||||||
может сохранять старую внутреннюю терминологию до обновления deployment.
|
|
||||||
|
|
||||||
## Security / Privacy Notes
|
## Security / Privacy Notes
|
||||||
|
|
||||||
@@ -332,20 +336,18 @@ Backlog/dead-letter:
|
|||||||
- raw JSON payload не коммитился;
|
- raw JSON payload не коммитился;
|
||||||
- screenshots с реальными данными не коммитились;
|
- screenshots с реальными данными не коммитились;
|
||||||
- реальные IP/hostname/usernames/ФИО/подразделения в этот документ не внесены;
|
- реальные IP/hostname/usernames/ФИО/подразделения в этот документ не внесены;
|
||||||
- проверка выполнялась read-only;
|
- deploy выполнялся controlled способом с backup старого binary и rollback path;
|
||||||
- destructive commands, restarts и deploy не выполнялись.
|
- destructive data operations не выполнялись;
|
||||||
|
- collectors, scoring rules и источники данных не менялись.
|
||||||
|
|
||||||
## Gaps
|
## Gaps
|
||||||
|
|
||||||
Критично перед расширением пилота:
|
Критично перед расширением пилота:
|
||||||
|
|
||||||
1. Закрыть deployment/version drift live portal runtime относительно Demo Freeze
|
1. Провести ручной разбор UEBA `critical` с evidence, не меняя правила вслепую.
|
||||||
v1.
|
2. Назначить операционного владельца live smoke, deploy parity и rollback.
|
||||||
2. После обновления runtime повторить production-hardening smoke на реальном
|
3. Зафиксировать регламент: после каждого deploy проверять binary/version,
|
||||||
контуре.
|
endpoint matrix и live smoke.
|
||||||
3. Проверить request id / correlation id headers на live API.
|
|
||||||
4. Проверить `/metrics` на live runtime и мониторинг low-cardinality metrics.
|
|
||||||
5. Провести ручной разбор UEBA `critical` с evidence, не меняя правила вслепую.
|
|
||||||
|
|
||||||
Желательно до пилотного расширения:
|
Желательно до пилотного расширения:
|
||||||
|
|
||||||
@@ -353,9 +355,7 @@ Backlog/dead-letter:
|
|||||||
эксплуатации и расследователей.
|
эксплуатации и расследователей.
|
||||||
2. Разделить freshness report по bucket types: active, inactive, event-driven,
|
2. Разделить freshness report по bucket types: active, inactive, event-driven,
|
||||||
historical.
|
historical.
|
||||||
3. Подготовить live validation checklist для deploy parity: repo commit,
|
3. Проверить Windows-side spool/backlog безопасной командой без раскрытия путей
|
||||||
deployed binary version, endpoint matrix, smoke results.
|
|
||||||
4. Проверить Windows-side spool/backlog безопасной командой без раскрытия путей
|
|
||||||
и payload.
|
и payload.
|
||||||
|
|
||||||
Можно перенести после первого ограниченного пилота:
|
Можно перенести после первого ограниченного пилота:
|
||||||
@@ -379,7 +379,7 @@ operations oriented:
|
|||||||
|
|
||||||
## Explicit Non-Goals
|
## Explicit Non-Goals
|
||||||
|
|
||||||
В рамках TASK_013 не выполнялись:
|
В рамках TASK_013/TASK_014 не выполнялись:
|
||||||
|
|
||||||
- новые API;
|
- новые API;
|
||||||
- новый UI;
|
- новый UI;
|
||||||
@@ -387,7 +387,7 @@ operations oriented:
|
|||||||
- ML/LLM;
|
- ML/LLM;
|
||||||
- DLP/SIEM/EDR claims;
|
- DLP/SIEM/EDR claims;
|
||||||
- изменение scoring logic;
|
- изменение scoring logic;
|
||||||
- restart/redeploy production services;
|
- изменение collectors или источников данных;
|
||||||
- выгрузка персональных данных;
|
- выгрузка персональных данных;
|
||||||
- сохранение real screenshots в git.
|
- сохранение real screenshots в git.
|
||||||
|
|
||||||
@@ -397,11 +397,12 @@ operations oriented:
|
|||||||
Portal, ActivityWatch, Security events, UEBA endpoint, Forensics и базовые role
|
Portal, ActivityWatch, Security events, UEBA endpoint, Forensics и базовые role
|
||||||
views частично подтверждены.
|
views частично подтверждены.
|
||||||
|
|
||||||
При этом live runtime не соответствует Demo Freeze v1 по production-hardening
|
После TASK_014 live runtime соответствует Demo Freeze v1 по production-hardening
|
||||||
endpoints и новым risk/explain/action endpoints. До расширения пилота нужно
|
endpoints, request/correlation headers, Explainable KPI, Risk Narrative,
|
||||||
закрыть deployment/version drift и повторить live validation. Текущий статус:
|
Executive Action Center и основным smoke-проверкам. Текущий статус:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
ready for controlled internal review;
|
ready for controlled internal pilot review;
|
||||||
not ready for expanded pilot until live runtime parity is restored.
|
ready for limited pilot preparation after manual UEBA evidence review and
|
||||||
|
operations ownership assignment.
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -29,16 +29,15 @@ headline, KPI label и CLI help используют публичное назв
|
|||||||
- Добавлен browser-level conformance smoke с Playwright и screenshots runtime
|
- Добавлен browser-level conformance smoke с Playwright и screenshots runtime
|
||||||
artifacts.
|
artifacts.
|
||||||
|
|
||||||
Оставшиеся acceptance gaps:
|
Оставшиеся acceptance gaps после TASK_014:
|
||||||
|
|
||||||
- Полная production-приемка требует live validation на стенде заказчика:
|
- Полная production-приемка требует live validation на стенде заказчика:
|
||||||
доступность, TLS/reverse proxy, источники данных, backup/restore и ownership
|
доступность, TLS/reverse proxy, источники данных, backup/restore и ownership
|
||||||
действий.
|
действий.
|
||||||
- TASK_013 live validation выявил deployment/version drift: рабочий внутренний
|
- TASK_013 live validation выявил deployment/version drift, но TASK_014 закрыл
|
||||||
runtime собирает и показывает реальные данные, но не соответствует Demo
|
его controlled deploy актуального portal binary и повторным live smoke.
|
||||||
Freeze v1 по production-hardening endpoints и отдельным risk/explain/action
|
- Перед расширением пилота остается ручной разбор UEBA evidence и закрепление
|
||||||
endpoints. До расширения пилота нужен controlled deploy/parity check и
|
операционного ownership за deploy parity, rollback и регулярными smoke.
|
||||||
повторный live smoke.
|
|
||||||
|
|
||||||
## Overall Status
|
## Overall Status
|
||||||
|
|
||||||
|
|||||||
@@ -63,3 +63,102 @@ PASS
|
|||||||
```
|
```
|
||||||
|
|
||||||
на живом контуре.
|
на живом контуре.
|
||||||
|
|
||||||
|
## Выполнение
|
||||||
|
|
||||||
|
Дата выполнения: 2026-06-07.
|
||||||
|
|
||||||
|
Статус: выполнено.
|
||||||
|
|
||||||
|
### Причина drift
|
||||||
|
|
||||||
|
Рабочий portal runtime на gateway host был запущен из устаревшего release
|
||||||
|
binary. Из-за этого live-контур не соответствовал Demo Freeze v1:
|
||||||
|
|
||||||
|
* production-hardening endpoints `/healthz`, `/readyz`, `/version`,
|
||||||
|
`/metrics` возвращали `404`;
|
||||||
|
* отдельные API `/portal/api/workforce/kpi/explain`,
|
||||||
|
`/portal/api/risk/narrative`, `/portal/api/actions` возвращали `404`;
|
||||||
|
* request/correlation headers отсутствовали на live API;
|
||||||
|
* browser conformance smoke видел старый Executive/Workforce/Security слой.
|
||||||
|
|
||||||
|
Кодовая база при этом уже содержала нужные контракты и UI-блоки. Проблема была
|
||||||
|
не в архитектуре и не в отсутствующем функционале, а в несовпадении deployed
|
||||||
|
binary с freeze-срезом.
|
||||||
|
|
||||||
|
### Ремедиация
|
||||||
|
|
||||||
|
Выполнен controlled deploy актуального release binary на gateway host:
|
||||||
|
|
||||||
|
* старый бинарник сохранен в backup-каталог на gateway host;
|
||||||
|
* новый release binary собран из текущей freeze-ветки;
|
||||||
|
* бинарник установлен в штатный путь portal service;
|
||||||
|
* `detmir-portal.service` перезапущен;
|
||||||
|
* rollback path сохранен через backup старого бинарника.
|
||||||
|
|
||||||
|
В репозиторий не добавлялись runtime payload, реальные logs, screenshots с
|
||||||
|
живыми данными, IP-адреса, hostname, логины, ФИО или подразделения.
|
||||||
|
|
||||||
|
### Live endpoint matrix после ремедиации
|
||||||
|
|
||||||
|
Проверено через gateway-local portal port:
|
||||||
|
|
||||||
|
| Endpoint | Результат |
|
||||||
|
| --- | --- |
|
||||||
|
| `/healthz` | `200` |
|
||||||
|
| `/readyz` | `200` |
|
||||||
|
| `/version` | `200` |
|
||||||
|
| `/metrics` | `200` |
|
||||||
|
| `/portal/api/health` | `200` |
|
||||||
|
| `/portal/api/reports?role=executive` | `200` |
|
||||||
|
| `/portal/api/workforce/kpi/explain` | `200` |
|
||||||
|
| `/portal/api/risk/narrative` | `200` |
|
||||||
|
| `/portal/api/actions` | `200` |
|
||||||
|
|
||||||
|
Также подтверждено:
|
||||||
|
|
||||||
|
* `X-Request-Id` возвращается;
|
||||||
|
* `X-Correlation-Id` возвращается;
|
||||||
|
* внешний gateway `/healthz` отвечает `200`;
|
||||||
|
* внешний `/portal/` остается закрыт авторизацией;
|
||||||
|
* свежий scan journal не показал panic, HTTP 500 или явных timeout.
|
||||||
|
|
||||||
|
### Smoke results
|
||||||
|
|
||||||
|
```text
|
||||||
|
AWATCH_PORTAL_SMOKE_URL=http://127.0.0.1:18720 \
|
||||||
|
node scripts/awatch-production-hardening-smoke.mjs
|
||||||
|
PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
AWATCH_BROWSER_SMOKE_URL=http://127.0.0.1:18720/portal/ \
|
||||||
|
AWATCH_BROWSER_SMOKE_ARTIFACT_DIR=/tmp/awatch-live-remediation-browser-smoke \
|
||||||
|
node scripts/browser-conformance-smoke.mjs
|
||||||
|
PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
DETMIR_PORTAL_SMOKE_URL=http://127.0.0.1:18720/portal/ \
|
||||||
|
node scripts/detmir-portal-tabs-smoke.mjs
|
||||||
|
PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test harness hardening
|
||||||
|
|
||||||
|
`scripts/browser-conformance-smoke.mjs` был усилен: после переключения роли он
|
||||||
|
ожидает фактические маркеры контента в `#content`, а не делает снимок через
|
||||||
|
фиксированную короткую задержку. Это устраняет ложный FAIL на холодной
|
||||||
|
асинхронной загрузке Executive/Security views.
|
||||||
|
|
||||||
|
Продуктовая бизнес-логика, API contracts, роли, scoring, collectors и
|
||||||
|
архитектура не менялись.
|
||||||
|
|
||||||
|
### Итог
|
||||||
|
|
||||||
|
```text
|
||||||
|
live runtime == documented runtime
|
||||||
|
live runtime == Demo Freeze v1
|
||||||
|
Browser smoke: PASS
|
||||||
|
Production hardening smoke: PASS
|
||||||
|
```
|
||||||
|
|||||||
@@ -70,11 +70,24 @@ async function switchView(page, selector, timeout) {
|
|||||||
selector.match(/data-view-mode="([^"]+)"/)?.[1] || "",
|
selector.match(/data-view-mode="([^"]+)"/)?.[1] || "",
|
||||||
{ timeout },
|
{ timeout },
|
||||||
);
|
);
|
||||||
await page.waitForTimeout(250);
|
}
|
||||||
|
|
||||||
|
async function waitForViewContent(page, spec, timeout) {
|
||||||
|
await page.waitForFunction(
|
||||||
|
({ markers, minLength }) => {
|
||||||
|
const content = document.querySelector("#content")?.innerText || "";
|
||||||
|
if (content.trim().length < minLength) return false;
|
||||||
|
const normalized = content.toLocaleLowerCase("ru-RU");
|
||||||
|
return markers.every((marker) => normalized.includes(String(marker).toLocaleLowerCase("ru-RU")));
|
||||||
|
},
|
||||||
|
{ markers: spec.required, minLength: 120 },
|
||||||
|
{ timeout },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkView(page, spec, artifactDir, timeout) {
|
async function checkView(page, spec, artifactDir, timeout) {
|
||||||
await switchView(page, `[data-view-mode="${spec.viewMode}"]`, timeout);
|
await switchView(page, `[data-view-mode="${spec.viewMode}"]`, timeout);
|
||||||
|
await waitForViewContent(page, spec, timeout);
|
||||||
const content = await page.locator("#content").innerText({ timeout });
|
const content = await page.locator("#content").innerText({ timeout });
|
||||||
const body = await page.locator("body").innerText({ timeout });
|
const body = await page.locator("body").innerText({ timeout });
|
||||||
const missing = missingMarkers(content, spec.required);
|
const missing = missingMarkers(content, spec.required);
|
||||||
|
|||||||
Reference in New Issue
Block a user