fix(ipsec): показывать неопределённый статус при общих Remote ID
This commit is contained in:
1 parent
7815e00a1c
commit
cb6ec09312
20 files changed
+1077
-15
No files matched your search
@@ -361,6 +361,7 @@ function IpsecPage({ selectedServerId, setSelectedServerId, workspaceTab, setWor
|
||||
|
||||
const serversWithIpsec = scopedSummaries.filter((s) => s.peers.length > 0).length
|
||||
const clientsOnline = scopedClients.filter((c) => c.online).length
|
||||
const clientsAmbiguous = scopedClients.filter(c => c.sessionAmbiguous).length
|
||||
const caOk = scopedSummaries.some((s) => s.caCert)
|
||||
const compactServer = effectiveServerId !== ALL_SERVERS_ID
|
||||
const sheetServerId = compactServer ? effectiveServerId : undefined
|
||||
@@ -690,7 +691,7 @@ function IpsecPage({ selectedServerId, setSelectedServerId, workspaceTab, setWor
|
||||
{
|
||||
id: "online",
|
||||
label: "Онлайн",
|
||||
value: scopeUnknown ? "—" : clientsOnline,
|
||||
value: scopeUnknown || clientsAmbiguous > 0 ? "—" : clientsOnline,
|
||||
icon: <ActivityIcon className="size-4" />,
|
||||
iconClassName: "text-success",
|
||||
},
|
||||
@@ -711,6 +712,12 @@ function IpsecPage({ selectedServerId, setSelectedServerId, workspaceTab, setWor
|
||||
{scopeWriteReceipt && <span data-source-time="write">Изменение подтверждено API: <time dateTime={scopeWriteReceipt.at} title={`Устройство ${scopeWriteReceipt.serverId}; подтверждение API не заменяет опрос`}>{formatReceipt(scopeWriteReceipt.at)}</time></span>}
|
||||
</div>}
|
||||
|
||||
{clientsAmbiguous > 0 && <Alert>
|
||||
<AlertCircleIcon />
|
||||
<AlertTitle>Статус части клиентов не определён</AlertTitle>
|
||||
<AlertDescription>У {clientsAmbiguous} клиентов совпадает идентификатор сессии. RouterOS не сообщает, какому из них принадлежит подключение. Проверьте Remote ID.</AlertDescription>
|
||||
</Alert>}
|
||||
|
||||
{isLive && (dataError || inventoryError) ? (
|
||||
<Alert variant="destructive">
|
||||
<AlertCircleIcon />
|
||||
|
||||
@@ -286,6 +286,13 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] {
|
||||
}
|
||||
|
||||
const out: IpsecClientDto[] = []
|
||||
const sessionClaims = new Map<RosIpsecActivePeer, IpsecClientDto[]>()
|
||||
const claimSession = (active: RosIpsecActivePeer | undefined) => {
|
||||
if (!active) return
|
||||
const claims = sessionClaims.get(active) ?? []
|
||||
claims.push(out[out.length - 1]!)
|
||||
sessionClaims.set(active, claims)
|
||||
}
|
||||
|
||||
// 1. Клиентские сертификаты (роль client), подписанные нашим CA / выданные менеджером / referenced identity.
|
||||
for (const cert of state.certs) {
|
||||
@@ -332,6 +339,7 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] {
|
||||
comment: comment || undefined,
|
||||
managed: isUser || isIpsecManagedComment(comment),
|
||||
})
|
||||
claimSession(active)
|
||||
}
|
||||
|
||||
// 2. PSK-identity (managed или IKEv2 remote-access).
|
||||
@@ -363,8 +371,20 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] {
|
||||
comment: i.comment || undefined,
|
||||
managed,
|
||||
})
|
||||
claimSession(active)
|
||||
}
|
||||
|
||||
// The native snapshot does not identify the configured identity/auth type.
|
||||
// Never assign one observed session/address to multiple catalog clients.
|
||||
for (const claims of sessionClaims.values()) {
|
||||
if (claims.length < 2) continue
|
||||
for (const client of claims) {
|
||||
client.online = false
|
||||
client.sessionAmbiguous = true
|
||||
client.activeAddress = undefined
|
||||
client.activeSince = undefined
|
||||
}
|
||||
}
|
||||
return out.sort((a, b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
@@ -443,6 +463,7 @@ export function mapServerSummary(state: IpsecServerState, clients: IpsecClientDt
|
||||
natRuleManaged,
|
||||
clientsTotal: clients.length,
|
||||
clientsOnline: clients.filter((c) => c.online).length,
|
||||
...(clients.some(c => c.sessionAmbiguous) ? { clientsSessionAmbiguous: clients.filter(c => c.sessionAmbiguous).length } : {}),
|
||||
certs: relevantCerts.map((c) => mapCertificate(c, roleCtx)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,4 +152,21 @@ namespaceState.active[0]!.id = "explicit.example"
|
||||
assert.equal(mapClients(namespaceState).find(c => c.certName === "ipsec-user-plain")?.online, true); checks++
|
||||
namespaceState.identities[0]!["remote-id"] = "unknown:explicit.example"
|
||||
assert.equal(mapClients(namespaceState).find(c => c.certName === "ipsec-user-plain")?.online, false); checks++
|
||||
const aliasesState = { ...sessionState, active: [{ ".id": "*ALIASED", id: "shared.example", state: "established", "dynamic-address": "198.18.112.250", uptime: "1m" }] } as typeof state
|
||||
for (const secondId of ["fqdn:shared.example", "key-id:shared.example"]) {
|
||||
aliasesState.identities = ["fqdn:shared.example", secondId].map((remoteId, n) => ({ ".id": "*PSK" + n, peer: "ike", "auth-method": "pre-shared-key", "remote-id": remoteId, comment: ipsecManagedComment("user=PSK" + n) }))
|
||||
const clients = mapClients(aliasesState)
|
||||
assert.equal(clients.length, 2)
|
||||
assert(clients.every(c => c.sessionAmbiguous && !c.online && !c.activeAddress && !c.activeSince)); checks++
|
||||
const summary = mapServerSummary(aliasesState, clients)
|
||||
assert.equal(summary.clientsOnline, 0); assert.equal(summary.clientsSessionAmbiguous, 2); checks++
|
||||
}
|
||||
aliasesState.certs = [{ ".id": "*CERTALIAS", name: "ipsec-user-aliased", "common-name": "certificate", ca: "ca", "key-usage": "tls-client" }]
|
||||
aliasesState.identities[0] = { ".id": "*CERTIDENTITY", peer: "ike", "auth-method": "digital-signature", "remote-certificate": "ipsec-user-aliased", "remote-id": "fqdn:shared.example" }
|
||||
assert(mapClients(aliasesState).every(c => c.sessionAmbiguous && !c.online && !c.activeAddress)); checks++
|
||||
aliasesState.identities[1]!["remote-id"] = "key-id:unrelated"
|
||||
const uniqueClients = mapClients(aliasesState)
|
||||
assert.equal(uniqueClients.find(c => c.kind === "cert")?.online, true)
|
||||
assert.equal(uniqueClients.find(c => c.kind === "psk")?.online, false)
|
||||
assert(uniqueClients.every(c => !c.sessionAmbiguous)); checks++
|
||||
console.log(`ipsec-state: ${checks} checks passed`)
|
||||
@@ -241,7 +241,7 @@ function IpsecServerGrid({
|
||||
</div>
|
||||
|
||||
<div className="mt-auto flex flex-col divide-y divide-border/60">
|
||||
<Row label="Клиенты" value={`${s.clientsOnline} онлайн / ${s.clientsTotal}`} />
|
||||
<Row label="Клиенты" value={s.clientsSessionAmbiguous ? `${s.clientsOnline} подтверждено онлайн / ${s.clientsTotal}; статус ${s.clientsSessionAmbiguous} не определён` : `${s.clientsOnline} онлайн / ${s.clientsTotal}`} />
|
||||
<Row label="Пул адресов" value={s.pool ? `${s.pool.name}: ${s.pool.ranges}` : "—"} />
|
||||
<Row label="NAT (интернет)" value={s.natRuleManaged ? "managed masquerade" : "нет правила"} mono={false} />
|
||||
<Row label="Managed IKEv2" value={s.initialized ? "инициализирован" : "не инициализирован"} mono={false} />
|
||||
|
||||
@@ -175,7 +175,7 @@ function IpsecUsersGrid({
|
||||
)}
|
||||
/>
|
||||
<span className={cn("font-mono text-[11px]", row.original.online ? "text-success" : "text-muted-foreground")}>
|
||||
{row.original.online ? row.original.activeAddress ?? "онлайн" : "офлайн"}
|
||||
{row.original.sessionAmbiguous ? "Не определено" : row.original.online ? row.original.activeAddress ?? "онлайн" : "офлайн"}
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# UX/UI: протокол внешней приёмки 12.5
|
||||
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.111 — буквальный CN больше не трактуется как typed Remote ID или чужой DN. Реальная одна сессия/два сертификата: только настоящий клиент online; explicit FQDN/SAN подключение подтверждено. Backend ux-id111/version1.0.0-test.id111, frontend ux-a11y101 прежний. State96/96, профильный IPsec/build/lint, live UI4/4 и cleanup13 коллекций×2 passed. Следующий112 — общие configured Remote IDs/коллизии aliases между identity и PSK; внешние Portal/Telegram ожидают настройки и разрешения.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.112 — одна native сессия не подтверждает online нескольким клиентам; certificate/PSK aliases получают sessionAmbiguous, «Не определено» и сводку «—» вместо ложного нуля. Backend ux-alias112/frontend ux-alias112-version, обе версии1.0.0-test.alias112. State102/102, профильные проверки/build, E2E14 unique+2 enhanced reruns, live4/4, recovery original online и cleanup13 коллекций×2 passed. Следующий113 — duplicate native IDs/сертификат с несколькими identity refs; внешние Portal/Telegram ожидают настройки/разрешения.12.5 открыт.
|
||||
|
||||
IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md).
|
||||
|
||||
@@ -1092,3 +1092,26 @@ Red-before state test остановился на ложном online; посл
|
||||
Обе native attempts сравнили baseline13 коллекций×2 после удаления собственных сертификатов, imported chain с уникальными именами, peer/identity/profile/proposal/group/template/mode-config/files. Cleanup passed, logging/default/public/metadata routes и исходный195.195.195.195/32CHR2 сохранены; passwords прежние, SSH/обаCHR доступны. Private P12/PEM/pass files удалены, приватные ключи/секреты не сохранены в evidence. Native helpers используют aggregate GET /api/ipsec, не selected observed-revision write.
|
||||
|
||||
Границы: shared configured Remote IDs, aliases нескольких identity/PSK с одинаковым bare value, arbitrary IKE ID types, custom DN/OIDs/client OS/full PKI/restore/IPv6 остаются открытыми. Этот блок принимает два конкретных CN fallback нарушения и одну real explicit-FQDN certificate сессию; не закрывает всю12.5. Следующий112 — коллизии configured Remote IDs между identity/PSK и безопасная атрибуция в этих случаях.
|
||||
|
||||
## 12.5.112 — IPsec: неоднозначные certificate/PSK Remote ID и понятный статус (2026-10-10)
|
||||
|
||||
Исправлена подтверждённая ошибка: одна реальная established сессия с bare FQDN ID и адресом198.18.112.250 учитывалась как два online-клиента — certificate с remote-id=fqdn:<имя>.example и PSK identity с remote-id=key-id:<имя>.example. В native снимке, используемом reader, нет подтверждения отдельной связи этой сессии с одним из этих двух catalog rows. Backend теперь собирает claims на каждый observed session object и при нескольких видимых владельцах не выбирает пользователя: online=false как «не подтверждено», sessionAmbiguous=true, activeAddress/activeSince удалены. Конфигурационные staticIp/Remote ID/IDs сохраняются; сетевые операции и допустимые конфигурации не запрещаются.
|
||||
|
||||
В @mmapp/contracts добавлены optional sessionAmbiguous и summary clientsSessionAmbiguous. Старые DTO остаются совместимыми; contradictory ambiguous+online/activeAddress/activeSince отвергается вместо ложного успеха. Summary clientsOnline — число подтверждённых строк, которое сопровождается ambiguous count. UI показывает «Не определено», пояснение Remote ID и «—» в KPI онлайн; карточка сервера подписывает число подтверждённых клиентов и неопределённых статусов. Это не offline и не ноль фактических сессий. Skill ReUI применён reuse-first: существующие Frame/KpiStatGrid/grid/Alert/semantic tokens, без vendor/theme/registry изменений. Source consumers изменены только для достоверного состояния данных.
|
||||
|
||||
Проверки: state102/102, test:ipsec8 scripts, backend/contracts TypeScript build и ESLint7 изменённых файлов passed. Первый локальный E2E startup не уложился120s, параллельный tsc увидел незавершённые generated .next route types. Старый dev cache перемещён в проверенный workspace tmp backup, пользовательские процессы/файлы не удалялись. Повтор E2E14/14 (data/freshness/layout,38.7s) passed; после добавления проверки server card только2 изменённых cases повторены (8.6s). Это14 unique accepted, не16 разных сценариев. Scoped source TypeScript passed с исключением generated cache; обе production builds отдельно прошли full build type-check. E2E проверяет unknown без offline/чужого IP, recovery и сохранение last-good при противоречивом DTO. Общая регрессия не повторялась.
|
||||
|
||||
[Native before/after/recovery](ux-ui/acceptance/ipsec-session-ambiguity-2026-10-10.json): собственная certificate FQDN/SAN пара, неиспользованный DN-looking CN certificate и дополнительная собственная PSK identity с другим typed prefix/тем же bare ID и отдельным mode-config198.18.112.251. На ux-id111 каталог присваивал одному native ID адрес198.18.112.250 обеим configured rows/clientsOnline2. Red-attempt и successful cleanup сохранены. На ux-alias112 две строки ambiguous, без active address/since; total3/confirmedOnline0/ambiguous2, third unused certificate остаётся offline. Native сессия established сохранялась. После exact-owner удаления только PSK identity/mode-config original снова online/198.18.112.250, sessionAmbiguous отсутствует; никаких автоматических network retries/rollback не добавлено.
|
||||
|
||||
[Live4/4](ux-ui/acceptance/browser-ipsec-alias-2026-10-10.json):1280/320×dark/light, actual root theme, unknown two rows/online KPI, unused certificate offline, reload, pageErrors0/no page overflow/applicationWrites0. Сначала functional4 cases прошли, но визуальная проверка обнаружила frontend vdev: APP_VERSION не тот build arg. Frontend пересобран с NEXT_PUBLIC_APP_VERSION=1.0.0-test.alias112, tag ux-alias112-version. Финальные4 cases повторены на этом image, desktop header version явно проверен; mobile header скрывает версию, отдельный version check там не заявлен. Скриншоты обновлены, light desktop/dark320 просмотрены. Preliminary functional/native result и ошибка версии не скрыты.
|
||||
|
||||
[Source/runtime manifest](ux-ui/acceptance/ipsec-alias-source-2026-10-10.json): backend context build-id111 +3 overrides, frontend build-a11y101 +4 overrides, общий contracts source;7 context byte hashes совпали, compiled backend mapper/contracts hashes2/2 совпали с контейнером. BaseHEAD7815e00 +working changes, labelalias112 неGitSHA; полный905-input audit/reproducible frontend binary не заявлены. Backend imagesha256:03e110dd414b575ad9a8f13f7b0302f241dbd3e439418c8ad1bbca7dc1c6fc9c, final frontend imagesha256:4bf4cad8b3c990a7259f84cf27fd6bb9ee34e3db904223b559c0559dbbe094a2; обе app versions1.0.0-test.alias112, backend/PG healthy, frontend running/HTTP/UI passed. Entry/node checks/pg_restore18.6 passed, приватный pre-alias112.env и старые images оставлены для rollback. Frontend построен дважды из-за исправления version arg; backend — один раз. DB migration/schema changes отсутствуют.
|
||||
|
||||
После обеих accepted runs удалены exact own IDs всех certificates/imported chain, peer/identity/profile/proposal/group/template/mode-config/export/upload files; private P12/PEM/pass файлы удалены. Baseline13 коллекций×2 совпал; logging/default/metadata/public routes/195.195.195.195/32 сохранены. Helpers используют aggregate GET /api/ipsec без observed revision writes, secrets не записывались в Git. ОбаCHR/SSH доступны, пароли прежние.
|
||||
|
||||
Границы: новое состояние относится к нескольким видимым clients, претендующим на одну observed сессию. Несколько native sessions с одинаковым ID, один certificate с несколькими identity refs, arbitrary ID types/custom OIDs/полнаяPKI/restore/client OS/IPv6 остаются отдельными пунктами. Следующий113 — эти две границы атрибуции одним профильным блоком;12.5 целиком открыт. Квота перед финальным блоком: использовано68% пятичасового/72% недельного.
|
||||
|
||||
| Референс | Применённая схема |
|
||||
| --- | --- |
|
||||
| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Native ID → claims → подтверждено либо «—» |
|
||||
| [ReUI Filtering2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp) | Контекст устройства → статус «Не определено» → пояснение → проверка Remote ID |
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
# План реализации UX/UI по пятичасовым окнам
|
||||
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.111 — буквальный CN больше не трактуется как typed Remote ID или чужой DN. Реальная одна сессия/два сертификата: только настоящий клиент online; explicit FQDN/SAN подключение подтверждено. Backend ux-id111/version1.0.0-test.id111, frontend ux-a11y101 прежний. State96/96, профильный IPsec/build/lint, live UI4/4 и cleanup13 коллекций×2 passed. Следующий112 — общие configured Remote IDs/коллизии aliases между identity и PSK; внешние Portal/Telegram ожидают настройки и разрешения.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.112 — одна native сессия не подтверждает online нескольким клиентам; certificate/PSK aliases получают sessionAmbiguous, «Не определено» и сводку «—» вместо ложного нуля. Backend ux-alias112/frontend ux-alias112-version, обе версии1.0.0-test.alias112. State102/102, профильные проверки/build, E2E14 unique+2 enhanced reruns, live4/4, recovery original online и cleanup13 коллекций×2 passed. Следующий113 — duplicate native IDs/сертификат с несколькими identity refs; внешние Portal/Telegram ожидают настройки/разрешения.12.5 открыт.
|
||||
|
||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-10
|
||||
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.111 — буквальный CN больше не трактуется как typed Remote ID или чужой DN. Реальная одна сессия/два сертификата: только настоящий клиент online; explicit FQDN/SAN подключение подтверждено. Backend ux-id111/version1.0.0-test.id111, frontend ux-a11y101 прежний. State96/96, профильный IPsec/build/lint, live UI4/4 и cleanup13 коллекций×2 passed. Следующий112 — общие configured Remote IDs/коллизии aliases между identity и PSK; внешние Portal/Telegram ожидают настройки и разрешения.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.112 — одна native сессия не подтверждает online нескольким клиентам; certificate/PSK aliases получают sessionAmbiguous, «Не определено» и сводку «—» вместо ложного нуля. Backend ux-alias112/frontend ux-alias112-version, обе версии1.0.0-test.alias112. State102/102, профильные проверки/build, E2E14 unique+2 enhanced reruns, live4/4, recovery original online и cleanup13 коллекций×2 passed. Следующий113 — duplicate native IDs/сертификат с несколькими identity refs; внешние Portal/Telegram ожидают настройки/разрешения.12.5 открыт.
|
||||
|
||||
Этапы0–11 завершены в локальных границах журнала. История выполненных внешних блоков и доказательства сохранены в [журнале](ux-ui-stage-12.md) и [протоколе](ux-ui-external-acceptance.md). Реальная Telegram доставка, Portal SSO, multi-instance и оставшиеся профильные сетевые ограничения открыты.
|
||||
|
||||
|
||||
+25
-2
@@ -1,6 +1,6 @@
|
||||
# UX/UI: журнал реализации
|
||||
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.111 — буквальный CN больше не трактуется как typed Remote ID или чужой DN. Реальная одна сессия/два сертификата: только настоящий клиент online; explicit FQDN/SAN подключение подтверждено. Backend ux-id111/version1.0.0-test.id111, frontend ux-a11y101 прежний. State96/96, профильный IPsec/build/lint, live UI4/4 и cleanup13 коллекций×2 passed. Следующий112 — общие configured Remote IDs/коллизии aliases между identity и PSK; внешние Portal/Telegram ожидают настройки и разрешения.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.112 — одна native сессия не подтверждает online нескольким клиентам; certificate/PSK aliases получают sessionAmbiguous, «Не определено» и сводку «—» вместо ложного нуля. Backend ux-alias112/frontend ux-alias112-version, обе версии1.0.0-test.alias112. State102/102, профильные проверки/build, E2E14 unique+2 enhanced reruns, live4/4, recovery original online и cleanup13 коллекций×2 passed. Следующий113 — duplicate native IDs/сертификат с несколькими identity refs; внешние Portal/Telegram ожидают настройки/разрешения.12.5 открыт.
|
||||
|
||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||
|
||||
@@ -36,7 +36,30 @@
|
||||
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
||||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–111 и ограничения ниже. Runtime backend ux-id111/frontend ux-a11y101. |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–112 и ограничения ниже. Runtime backend ux-alias112/frontend ux-alias112-version. |
|
||||
|
||||
## 12.5.112 — IPsec: неоднозначные certificate/PSK Remote ID и понятный статус (2026-10-10)
|
||||
|
||||
Исправлена подтверждённая ошибка: одна реальная established сессия с bare FQDN ID и адресом198.18.112.250 учитывалась как два online-клиента — certificate с remote-id=fqdn:<имя>.example и PSK identity с remote-id=key-id:<имя>.example. В native снимке, используемом reader, нет подтверждения отдельной связи этой сессии с одним из этих двух catalog rows. Backend теперь собирает claims на каждый observed session object и при нескольких видимых владельцах не выбирает пользователя: online=false как «не подтверждено», sessionAmbiguous=true, activeAddress/activeSince удалены. Конфигурационные staticIp/Remote ID/IDs сохраняются; сетевые операции и допустимые конфигурации не запрещаются.
|
||||
|
||||
В @mmapp/contracts добавлены optional sessionAmbiguous и summary clientsSessionAmbiguous. Старые DTO остаются совместимыми; contradictory ambiguous+online/activeAddress/activeSince отвергается вместо ложного успеха. Summary clientsOnline — число подтверждённых строк, которое сопровождается ambiguous count. UI показывает «Не определено», пояснение Remote ID и «—» в KPI онлайн; карточка сервера подписывает число подтверждённых клиентов и неопределённых статусов. Это не offline и не ноль фактических сессий. Skill ReUI применён reuse-first: существующие Frame/KpiStatGrid/grid/Alert/semantic tokens, без vendor/theme/registry изменений. Source consumers изменены только для достоверного состояния данных.
|
||||
|
||||
Проверки: state102/102, test:ipsec8 scripts, backend/contracts TypeScript build и ESLint7 изменённых файлов passed. Первый локальный E2E startup не уложился120s, параллельный tsc увидел незавершённые generated .next route types. Старый dev cache перемещён в проверенный workspace tmp backup, пользовательские процессы/файлы не удалялись. Повтор E2E14/14 (data/freshness/layout,38.7s) passed; после добавления проверки server card только2 изменённых cases повторены (8.6s). Это14 unique accepted, не16 разных сценариев. Scoped source TypeScript passed с исключением generated cache; обе production builds отдельно прошли full build type-check. E2E проверяет unknown без offline/чужого IP, recovery и сохранение last-good при противоречивом DTO. Общая регрессия не повторялась.
|
||||
|
||||
[Native before/after/recovery](ux-ui/acceptance/ipsec-session-ambiguity-2026-10-10.json): собственная certificate FQDN/SAN пара, неиспользованный DN-looking CN certificate и дополнительная собственная PSK identity с другим typed prefix/тем же bare ID и отдельным mode-config198.18.112.251. На ux-id111 каталог присваивал одному native ID адрес198.18.112.250 обеим configured rows/clientsOnline2. Red-attempt и successful cleanup сохранены. На ux-alias112 две строки ambiguous, без active address/since; total3/confirmedOnline0/ambiguous2, third unused certificate остаётся offline. Native сессия established сохранялась. После exact-owner удаления только PSK identity/mode-config original снова online/198.18.112.250, sessionAmbiguous отсутствует; никаких автоматических network retries/rollback не добавлено.
|
||||
|
||||
[Live4/4](ux-ui/acceptance/browser-ipsec-alias-2026-10-10.json):1280/320×dark/light, actual root theme, unknown two rows/online KPI, unused certificate offline, reload, pageErrors0/no page overflow/applicationWrites0. Сначала functional4 cases прошли, но визуальная проверка обнаружила frontend vdev: APP_VERSION не тот build arg. Frontend пересобран с NEXT_PUBLIC_APP_VERSION=1.0.0-test.alias112, tag ux-alias112-version. Финальные4 cases повторены на этом image, desktop header version явно проверен; mobile header скрывает версию, отдельный version check там не заявлен. Скриншоты обновлены, light desktop/dark320 просмотрены. Preliminary functional/native result и ошибка версии не скрыты.
|
||||
|
||||
[Source/runtime manifest](ux-ui/acceptance/ipsec-alias-source-2026-10-10.json): backend context build-id111 +3 overrides, frontend build-a11y101 +4 overrides, общий contracts source;7 context byte hashes совпали, compiled backend mapper/contracts hashes2/2 совпали с контейнером. BaseHEAD7815e00 +working changes, labelalias112 неGitSHA; полный905-input audit/reproducible frontend binary не заявлены. Backend imagesha256:03e110dd414b575ad9a8f13f7b0302f241dbd3e439418c8ad1bbca7dc1c6fc9c, final frontend imagesha256:4bf4cad8b3c990a7259f84cf27fd6bb9ee34e3db904223b559c0559dbbe094a2; обе app versions1.0.0-test.alias112, backend/PG healthy, frontend running/HTTP/UI passed. Entry/node checks/pg_restore18.6 passed, приватный pre-alias112.env и старые images оставлены для rollback. Frontend построен дважды из-за исправления version arg; backend — один раз. DB migration/schema changes отсутствуют.
|
||||
|
||||
После обеих accepted runs удалены exact own IDs всех certificates/imported chain, peer/identity/profile/proposal/group/template/mode-config/export/upload files; private P12/PEM/pass файлы удалены. Baseline13 коллекций×2 совпал; logging/default/metadata/public routes/195.195.195.195/32 сохранены. Helpers используют aggregate GET /api/ipsec без observed revision writes, secrets не записывались в Git. ОбаCHR/SSH доступны, пароли прежние.
|
||||
|
||||
Границы: новое состояние относится к нескольким видимым clients, претендующим на одну observed сессию. Несколько native sessions с одинаковым ID, один certificate с несколькими identity refs, arbitrary ID types/custom OIDs/полнаяPKI/restore/client OS/IPv6 остаются отдельными пунктами. Следующий113 — эти две границы атрибуции одним профильным блоком;12.5 целиком открыт. Квота перед финальным блоком: использовано68% пятичасового/72% недельного.
|
||||
|
||||
| Референс | Применённая схема |
|
||||
| --- | --- |
|
||||
| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Native ID → claims → подтверждено либо «—» |
|
||||
| [ReUI Filtering2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp) | Контекст устройства → статус «Не определено» → пояснение → проверка Remote ID |
|
||||
|
||||
## 12.5.111 — IPsec: буквальный CN, чужой DN и явно настроенный FQDN ID (2026-10-10)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Оставшаяся внешняя приёмка — 2026-10-10
|
||||
|
||||
Это актуальная матрица после 12.5.111. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
Это актуальная матрица после 12.5.112. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-id111`, frontend `ux-a11y101`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты111 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-alias112`, frontend `ux-alias112-version`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||
|
||||
| Раздел | Подтверждено | Осталось / условие завершения |
|
||||
| --- | --- | --- |
|
||||
@@ -12,7 +12,7 @@
|
||||
| GRE | Native lifecycle, metadata, live формы/меню/URL/Ping53–57; GRE используется в OSPF/BGP/IPsec последующих блоков; native IPv6 ULA inner109 | IPv6 outer и application IPv6 interface address lifecycle, независимые WAN, масштаб и длительное восстановление; принятие GRE не означает приёмку всех сценариев автоматического расписания |
|
||||
| WireGuard | Native handshake/data plane58, deletion60, live create/peer/disable/enable/delete62, mobile64, export/import67–74; native IPv6 ULA inner/allowedIps/handshake109 | Клиентские ОС и произвольные конфигурации, IPv6 outer/scale и application IPv6 interface address lifecycle, физический lost ACK и устойчивое восстановление; `.conf` с placeholders — шаблон, не принятый клиентский tunnel |
|
||||
| VXLAN | Собственная пара/private Ping/catalog/URL/export75–76; bridge/FDB/port loss/recovery107; IPv6 ULA inner по IPv4 outer108 | API приложения read-only: create/delete проверены native. IPv6 outer, масштаб/производительность, профильные mutation RBAC/concurrency отдельно не приняты |
|
||||
| IPsec | PSK и сертификатное шифрование77–82, active peer/online/mode-config, scoped NAT/group, partial/unknown/applied receipts, restore conflicts, JWT; full DN/специальные символы/online110; literal CN namespace guards и explicit FQDN111 | Клиентские Windows/macOS/iOS/Android, прочие DN форматы/custom OIDs/IKE ID namespaces, полная PKI и policy/profile/proposal restore, физический disconnect, durable retry/multi-instance, IPv6/maximum throughput |
|
||||
| IPsec | PSK и сертификатное шифрование77–82, active peer/online/mode-config, scoped NAT/group, partial/unknown/applied receipts, restore conflicts, JWT; full DN/специальные символы/online110; literal CN namespace guards и explicit FQDN111; certificate/PSK shared ID unknown/recovery112 | Клиентские Windows/macOS/iOS/Android, прочие DN форматы/custom OIDs/IKE ID namespaces, полная PKI и policy/profile/proposal restore, физический disconnect, durable retry/multi-instance, IPv6/maximum throughput |
|
||||
| OSPF/BFD | Real Full/own routes84–85, раздельные наблюдения BFD86, effective disabled/optimizer cost/partial/RBAC87, alternate path90 и CIDR91 | Sustained BFD-only gate не принят: в86 сосед мог вновь статьFull при доступныхHello. В90 переходный Ping18/40 с55% loss: бесшовность не принята. REST timing — наблюдаемая граница, не SLA; IPv6/scale/independent WAN открыты |
|
||||
| BGP | Established83, exact /32 exchange/API/UI/administrative withdrawal92, BFD primary GRE loss/alternate/recovery93 | Hold timer/TCP loss безBFD принят104; packet loss в переходе, разные внешние peers/WAN policy, IPv6/scale. Два логических пути используют тот же public WAN; physical redundancy не принята |
|
||||
| Recursive routes | Production PUT/change/own history restore88, disabled guards, partial/unknown/applied outcomes, live формы/контекст | Автоматический rollback/retry, durable receipts и несколько экземпляров отсутствуют; PUT не является idempotent noop. Полная произвольная legacy catalog миграция не принята |
|
||||
@@ -25,7 +25,7 @@
|
||||
## Следующая последовательность
|
||||
|
||||
1. **12.5.95 завершён:** [source/context/compiled audit](ux-ui/acceptance/deployment-source-audit-2026-10-10.json), production source drift не выявлен; нормализация и исключения явно указаны.
|
||||
2. **12.5.96 timezone завершён:** [6 live UI cases](ux-ui/acceptance/browser-speed-timezone-2026-10-10.json). 97 HTTP receipt disconnect принят: [протокол](ux-ui/acceptance/speed-disconnect-2026-10-10.json). 98 сообщение неизвестного native результата исправлено/развёрнуто. 99 main/context завершён с точной записью одного failure/delta;100 transport и101 accessibility исправлены/развёрнуты.102 malformed PATCH исправлен/принят.103 packet rows/public/GRE приняты в границах коротких samples; initial loss/root cause остаётся открытым.104 hold/TCP loss/recovery принят.105 source/runtime/evidence сверка passed.106 read-only readiness: auth disabled/Portal localhost/bot and chat unconfigured.107 — native bridge/FDB/loss/recovery принят.108 — IPv6 inner VXLAN принят, initial0/3 и1/3 остаются в протоколе;109 — native GRE/WireGuard IPv6 inner принят; readers /ip/address не показывают native IPv6 interface addresses.110 — полный native DN/online исправлен и принят;111 — literal CN guards/real explicit FQDN accepted;112 — shared configured ID/identity-PSK aliases. Реальные интеграции требуют тестовых доступов и отдельного разрешения на сообщение.
|
||||
2. **12.5.96 timezone завершён:** [6 live UI cases](ux-ui/acceptance/browser-speed-timezone-2026-10-10.json). 97 HTTP receipt disconnect принят: [протокол](ux-ui/acceptance/speed-disconnect-2026-10-10.json). 98 сообщение неизвестного native результата исправлено/развёрнуто. 99 main/context завершён с точной записью одного failure/delta;100 transport и101 accessibility исправлены/развёрнуты.102 malformed PATCH исправлен/принят.103 packet rows/public/GRE приняты в границах коротких samples; initial loss/root cause остаётся открытым.104 hold/TCP loss/recovery принят.105 source/runtime/evidence сверка passed.106 read-only readiness: auth disabled/Portal localhost/bot and chat unconfigured.107 — native bridge/FDB/loss/recovery принят.108 — IPv6 inner VXLAN принят, initial0/3 и1/3 остаются в протоколе;109 — native GRE/WireGuard IPv6 inner принят; readers /ip/address не показывают native IPv6 interface addresses.110 — полный native DN/online исправлен и принят;111 — literal CN guards/real explicit FQDN accepted;112 — certificate/PSK alias ambiguity marked unknown/recovery accepted;113 — duplicate native IDs/multiple identity refs. Реальные интеграции требуют тестовых доступов и отдельного разрешения на сообщение.
|
||||
3. **Заключительный профильный контроль:** после последнего исправления собрать только затронутую часть, проверить её live и обновить матрицу. Общую регрессию выполнить один раз на согласованном runtime.
|
||||
4. **Внешние зависимости:** Telegram/Portal/client OS/multi-WAN/scale проходят отдельную приёмку при наличии нужных аккаунтов, устройств и разрешений. Лабораторный результат двух CHR не закрывает их автоматически.
|
||||
|
||||
|
||||
+24
-1
@@ -1,6 +1,6 @@
|
||||
# Этап 12: итоговая приёмка UX/UI
|
||||
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.111 — буквальный CN больше не трактуется как typed Remote ID или чужой DN. Реальная одна сессия/два сертификата: только настоящий клиент online; explicit FQDN/SAN подключение подтверждено. Backend ux-id111/version1.0.0-test.id111, frontend ux-a11y101 прежний. State96/96, профильный IPsec/build/lint, live UI4/4 и cleanup13 коллекций×2 passed. Следующий112 — общие configured Remote IDs/коллизии aliases между identity и PSK; внешние Portal/Telegram ожидают настройки и разрешения.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-10: завершён12.5.112 — одна native сессия не подтверждает online нескольким клиентам; certificate/PSK aliases получают sessionAmbiguous, «Не определено» и сводку «—» вместо ложного нуля. Backend ux-alias112/frontend ux-alias112-version, обе версии1.0.0-test.alias112. State102/102, профильные проверки/build, E2E14 unique+2 enhanced reruns, live4/4, recovery original online и cleanup13 коллекций×2 passed. Следующий113 — duplicate native IDs/сертификат с несколькими identity refs; внешние Portal/Telegram ожидают настройки/разрешения.12.5 открыт.
|
||||
|
||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||
|
||||
@@ -2397,3 +2397,26 @@ Red-before state test остановился на ложном online; посл
|
||||
Обе native attempts сравнили baseline13 коллекций×2 после удаления собственных сертификатов, imported chain с уникальными именами, peer/identity/profile/proposal/group/template/mode-config/files. Cleanup passed, logging/default/public/metadata routes и исходный195.195.195.195/32CHR2 сохранены; passwords прежние, SSH/обаCHR доступны. Private P12/PEM/pass files удалены, приватные ключи/секреты не сохранены в evidence. Native helpers используют aggregate GET /api/ipsec, не selected observed-revision write.
|
||||
|
||||
Границы: shared configured Remote IDs, aliases нескольких identity/PSK с одинаковым bare value, arbitrary IKE ID types, custom DN/OIDs/client OS/full PKI/restore/IPv6 остаются открытыми. Этот блок принимает два конкретных CN fallback нарушения и одну real explicit-FQDN certificate сессию; не закрывает всю12.5. Следующий112 — коллизии configured Remote IDs между identity/PSK и безопасная атрибуция в этих случаях.
|
||||
|
||||
## 12.5.112 — IPsec: неоднозначные certificate/PSK Remote ID и понятный статус (2026-10-10)
|
||||
|
||||
Исправлена подтверждённая ошибка: одна реальная established сессия с bare FQDN ID и адресом198.18.112.250 учитывалась как два online-клиента — certificate с remote-id=fqdn:<имя>.example и PSK identity с remote-id=key-id:<имя>.example. В native снимке, используемом reader, нет подтверждения отдельной связи этой сессии с одним из этих двух catalog rows. Backend теперь собирает claims на каждый observed session object и при нескольких видимых владельцах не выбирает пользователя: online=false как «не подтверждено», sessionAmbiguous=true, activeAddress/activeSince удалены. Конфигурационные staticIp/Remote ID/IDs сохраняются; сетевые операции и допустимые конфигурации не запрещаются.
|
||||
|
||||
В @mmapp/contracts добавлены optional sessionAmbiguous и summary clientsSessionAmbiguous. Старые DTO остаются совместимыми; contradictory ambiguous+online/activeAddress/activeSince отвергается вместо ложного успеха. Summary clientsOnline — число подтверждённых строк, которое сопровождается ambiguous count. UI показывает «Не определено», пояснение Remote ID и «—» в KPI онлайн; карточка сервера подписывает число подтверждённых клиентов и неопределённых статусов. Это не offline и не ноль фактических сессий. Skill ReUI применён reuse-first: существующие Frame/KpiStatGrid/grid/Alert/semantic tokens, без vendor/theme/registry изменений. Source consumers изменены только для достоверного состояния данных.
|
||||
|
||||
Проверки: state102/102, test:ipsec8 scripts, backend/contracts TypeScript build и ESLint7 изменённых файлов passed. Первый локальный E2E startup не уложился120s, параллельный tsc увидел незавершённые generated .next route types. Старый dev cache перемещён в проверенный workspace tmp backup, пользовательские процессы/файлы не удалялись. Повтор E2E14/14 (data/freshness/layout,38.7s) passed; после добавления проверки server card только2 изменённых cases повторены (8.6s). Это14 unique accepted, не16 разных сценариев. Scoped source TypeScript passed с исключением generated cache; обе production builds отдельно прошли full build type-check. E2E проверяет unknown без offline/чужого IP, recovery и сохранение last-good при противоречивом DTO. Общая регрессия не повторялась.
|
||||
|
||||
[Native before/after/recovery](ux-ui/acceptance/ipsec-session-ambiguity-2026-10-10.json): собственная certificate FQDN/SAN пара, неиспользованный DN-looking CN certificate и дополнительная собственная PSK identity с другим typed prefix/тем же bare ID и отдельным mode-config198.18.112.251. На ux-id111 каталог присваивал одному native ID адрес198.18.112.250 обеим configured rows/clientsOnline2. Red-attempt и successful cleanup сохранены. На ux-alias112 две строки ambiguous, без active address/since; total3/confirmedOnline0/ambiguous2, third unused certificate остаётся offline. Native сессия established сохранялась. После exact-owner удаления только PSK identity/mode-config original снова online/198.18.112.250, sessionAmbiguous отсутствует; никаких автоматических network retries/rollback не добавлено.
|
||||
|
||||
[Live4/4](ux-ui/acceptance/browser-ipsec-alias-2026-10-10.json):1280/320×dark/light, actual root theme, unknown two rows/online KPI, unused certificate offline, reload, pageErrors0/no page overflow/applicationWrites0. Сначала functional4 cases прошли, но визуальная проверка обнаружила frontend vdev: APP_VERSION не тот build arg. Frontend пересобран с NEXT_PUBLIC_APP_VERSION=1.0.0-test.alias112, tag ux-alias112-version. Финальные4 cases повторены на этом image, desktop header version явно проверен; mobile header скрывает версию, отдельный version check там не заявлен. Скриншоты обновлены, light desktop/dark320 просмотрены. Preliminary functional/native result и ошибка версии не скрыты.
|
||||
|
||||
[Source/runtime manifest](ux-ui/acceptance/ipsec-alias-source-2026-10-10.json): backend context build-id111 +3 overrides, frontend build-a11y101 +4 overrides, общий contracts source;7 context byte hashes совпали, compiled backend mapper/contracts hashes2/2 совпали с контейнером. BaseHEAD7815e00 +working changes, labelalias112 неGitSHA; полный905-input audit/reproducible frontend binary не заявлены. Backend imagesha256:03e110dd414b575ad9a8f13f7b0302f241dbd3e439418c8ad1bbca7dc1c6fc9c, final frontend imagesha256:4bf4cad8b3c990a7259f84cf27fd6bb9ee34e3db904223b559c0559dbbe094a2; обе app versions1.0.0-test.alias112, backend/PG healthy, frontend running/HTTP/UI passed. Entry/node checks/pg_restore18.6 passed, приватный pre-alias112.env и старые images оставлены для rollback. Frontend построен дважды из-за исправления version arg; backend — один раз. DB migration/schema changes отсутствуют.
|
||||
|
||||
После обеих accepted runs удалены exact own IDs всех certificates/imported chain, peer/identity/profile/proposal/group/template/mode-config/export/upload files; private P12/PEM/pass файлы удалены. Baseline13 коллекций×2 совпал; logging/default/metadata/public routes/195.195.195.195/32 сохранены. Helpers используют aggregate GET /api/ipsec без observed revision writes, secrets не записывались в Git. ОбаCHR/SSH доступны, пароли прежние.
|
||||
|
||||
Границы: новое состояние относится к нескольким видимым clients, претендующим на одну observed сессию. Несколько native sessions с одинаковым ID, один certificate с несколькими identity refs, arbitrary ID types/custom OIDs/полнаяPKI/restore/client OS/IPv6 остаются отдельными пунктами. Следующий113 — эти две границы атрибуции одним профильным блоком;12.5 целиком открыт. Квота перед финальным блоком: использовано68% пятичасового/72% недельного.
|
||||
|
||||
| Референс | Применённая схема |
|
||||
| --- | --- |
|
||||
| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Native ID → claims → подтверждено либо «—» |
|
||||
| [ReUI Filtering2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp) | Контекст устройства → статус «Не определено» → пояснение → проверка Remote ID |
|
||||
@@ -1,6 +1,6 @@
|
||||
# Тестовый сервер UX/UI — 2026-10-10
|
||||
|
||||
Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-id111/version1.0.0-test.id111, frontend ux-a11y101/version1.0.0-test.a11y101; backend/PG healthy, frontend HTTP/browser passed. VPN107–109 и IPsec110–111: bridge/FDB/IPv6 inner и исправление online по DN/CN и explicit FQDN приняты в границах журнала; собственные объекты удалены, baseline восстановлен; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние.
|
||||
Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-alias112/version1.0.0-test.alias112, frontend ux-alias112-version/version1.0.0-test.alias112; backend/PG healthy, frontend HTTP/browser passed. VPN107–109 и IPsec110–112: bridge/FDB/IPv6 inner и исправление online по DN/CN, explicit FQDN и unknown при shared ID приняты в границах журнала; собственные объекты удалены, baseline восстановлен; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние.
|
||||
|
||||
| Параметр | Проверенное состояние |
|
||||
| --- | --- |
|
||||
@@ -14,7 +14,7 @@
|
||||
| PostgreSQL | postgres:18-alpine,18.6;mmapp-test-postgres healthy;SELECT version() passed |
|
||||
| Данные | Отдельный Compose project mmapp-test,том mmapp-test_mmapp-pgdata и каталог ./data |
|
||||
| Доступ | PostgreSQL не публикуется;frontend3000/backend8000 привязаны к127.0.0.1 после запуска |
|
||||
| Образы приложения | mmapp-test/backend:ux-id111 и mmapp-test/frontend:ux-a11y101; запущены |
|
||||
| Образы приложения | mmapp-test/backend:ux-alias112 и mmapp-test/frontend:ux-alias112-version; запущены |
|
||||
|
||||
Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example).
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"date": "2026-10-10",
|
||||
"runtime": {
|
||||
"backend": "ux-alias112",
|
||||
"frontend": "ux-alias112-version"
|
||||
},
|
||||
"httpMocks": false,
|
||||
"cases": [
|
||||
{
|
||||
"theme": "dark",
|
||||
"width": 1280,
|
||||
"rootThemeConfirmed": true,
|
||||
"versionConfirmed": true,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
},
|
||||
{
|
||||
"theme": "dark",
|
||||
"width": 320,
|
||||
"rootThemeConfirmed": true,
|
||||
"versionConfirmed": false,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
},
|
||||
{
|
||||
"theme": "light",
|
||||
"width": 1280,
|
||||
"rootThemeConfirmed": true,
|
||||
"versionConfirmed": true,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
},
|
||||
{
|
||||
"theme": "light",
|
||||
"width": 320,
|
||||
"rootThemeConfirmed": true,
|
||||
"versionConfirmed": false,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
}
|
||||
],
|
||||
"pageErrors": [],
|
||||
"applicationWrites": [],
|
||||
"scope": "Real certificate/PSK alias ambiguity, unknown row statuses and online count, reload, desktop/mobile, two themes"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"date": "2026-10-10",
|
||||
"baseCommit": "7815e00",
|
||||
"backendBase": "build-id111",
|
||||
"frontendBase": "build-a11y101",
|
||||
"backendContext": "build-alias112",
|
||||
"frontendContext": "build-alias112-front",
|
||||
"source": "Explicit working-file overrides; revision label alias112 is not a Git SHA",
|
||||
"contextHashes": {
|
||||
"backend": {
|
||||
"backend/src/services/ipsec-live.ts": "7f5cccea14c63e96aa9774beab28257a9a81d624cc15a7ef88d19e17e25d5fd2",
|
||||
"backend/src/services/ipsec-state.test.ts": "8a0f19b3a16962a2217ac76bfd4c1009813f59cf9e50a4b90fb31165ff6a9a6d",
|
||||
"packages/contracts/src/ipsec.ts": "17f9fdcd528fba5fc5df539ca4392bdcd98d99957b1273e83c51537efa1630e5"
|
||||
},
|
||||
"frontend": {
|
||||
"app/(main)/ipsec/page.tsx": "2673411a60fd1796389ddbb6cba37a16b607af87fceedfc37e89e18717fd013e",
|
||||
"components/ipsec/ipsec-users-grid.tsx": "75a4f4c7f66badbc425669114982fbd067121e93ecf7800e02b3c8da83d80cfe",
|
||||
"components/ipsec/ipsec-server-grid.tsx": "c48e55cb0e63c9b7ca55f6277b194aa748bc7b40982459cdb9c4fe331df68011",
|
||||
"packages/contracts/src/ipsec.ts": "17f9fdcd528fba5fc5df539ca4392bdcd98d99957b1273e83c51537efa1630e5"
|
||||
}
|
||||
},
|
||||
"contextByteHashesMatch": true,
|
||||
"compiled": [
|
||||
{
|
||||
"path": "backend/dist/services/ipsec-live.js",
|
||||
"sha256": "0c8f4e50290df15dd1cc62bcdb8879c8f05025cfc7e29731ee486e472fa6a5fe",
|
||||
"backendContainerByteHashMatches": true
|
||||
},
|
||||
{
|
||||
"path": "packages/contracts/dist/ipsec.js",
|
||||
"sha256": "e9a9f21e6b6e19831380981108303b37ce82159575e7e198e66711ffdae576a6",
|
||||
"backendContainerByteHashMatches": true
|
||||
}
|
||||
],
|
||||
"deployment": {
|
||||
"backendImage": "sha256:03e110dd414b575ad9a8f13f7b0302f241dbd3e439418c8ad1bbca7dc1c6fc9c",
|
||||
"frontendImage": "sha256:4bf4cad8b3c990a7259f84cf27fd6bb9ee34e3db904223b559c0559dbbe094a2",
|
||||
"revisionLabel": "alias112",
|
||||
"health": {
|
||||
"status": "ok",
|
||||
"timestamp": "2026-10-10T03:19:59.783Z",
|
||||
"version": "1.0.0-test.alias112",
|
||||
"eventLoopDelayMs": 20,
|
||||
"flowWorker": {
|
||||
"alive": false,
|
||||
"bound": false,
|
||||
"pendingSize": 0,
|
||||
"dropped": 0,
|
||||
"packetsReceived": 0
|
||||
}
|
||||
},
|
||||
"contextHashes": {
|
||||
"backend": {
|
||||
"backend/src/services/ipsec-live.ts": "7f5cccea14c63e96aa9774beab28257a9a81d624cc15a7ef88d19e17e25d5fd2",
|
||||
"backend/src/services/ipsec-state.test.ts": "8a0f19b3a16962a2217ac76bfd4c1009813f59cf9e50a4b90fb31165ff6a9a6d",
|
||||
"packages/contracts/src/ipsec.ts": "17f9fdcd528fba5fc5df539ca4392bdcd98d99957b1273e83c51537efa1630e5"
|
||||
},
|
||||
"frontend": {
|
||||
"app/(main)/ipsec/page.tsx": "2673411a60fd1796389ddbb6cba37a16b607af87fceedfc37e89e18717fd013e",
|
||||
"components/ipsec/ipsec-users-grid.tsx": "75a4f4c7f66badbc425669114982fbd067121e93ecf7800e02b3c8da83d80cfe",
|
||||
"components/ipsec/ipsec-server-grid.tsx": "c48e55cb0e63c9b7ca55f6277b194aa748bc7b40982459cdb9c4fe331df68011",
|
||||
"packages/contracts/src/ipsec.ts": "17f9fdcd528fba5fc5df539ca4392bdcd98d99957b1273e83c51537efa1630e5"
|
||||
}
|
||||
},
|
||||
"frontendInitialImage": "sha256:0cf246b79dd054e5ecb4ce692d82badc3324211615fb9313aaa7b6dbfc2881f9",
|
||||
"frontendTag": "ux-alias112-version",
|
||||
"frontendVersion": "1.0.0-test.alias112"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,779 @@
|
||||
{
|
||||
"date": "2026-10-10",
|
||||
"block": "12.5.112",
|
||||
"runtime": {
|
||||
"backend": "ux-alias112",
|
||||
"frontend": "ux-alias112-version",
|
||||
"version": "1.0.0-test.alias112"
|
||||
},
|
||||
"before": {
|
||||
"date": "2026-10-10",
|
||||
"block": "12.5.112",
|
||||
"name": "mm-ipsec112-1791601534901",
|
||||
"cn": "mm-ipsec112-1791601534901",
|
||||
"observations": [
|
||||
{
|
||||
"serverId": 1,
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "CN=mm-ipsec112-1791601534901",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250",
|
||||
"remote-address": "104.165.244.7",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"catalog": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791601534901",
|
||||
"commonName": "CN=mm-ipsec112-1791601534901",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791601534901-decoy",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901",
|
||||
"commonName": "mm-ipsec112-1791601534901",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791601534901",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"serverId": 2,
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "194.226.121.150",
|
||||
"state": "established",
|
||||
"remote-address": "194.226.121.150",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"catalog": []
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
{
|
||||
"serverId": 1,
|
||||
"/system/logging": true,
|
||||
"/ip/ipsec/identity": true,
|
||||
"/ip/ipsec/peer": true,
|
||||
"/ip/ipsec/policy": true,
|
||||
"/ip/ipsec/policy/group": true,
|
||||
"/ip/ipsec/mode-config": true,
|
||||
"/ip/ipsec/proposal": true,
|
||||
"/ip/ipsec/profile": true,
|
||||
"/certificate": true,
|
||||
"/file": true,
|
||||
"/ip/address": true,
|
||||
"/ip/route": true,
|
||||
"/ip/firewall/nat": true
|
||||
},
|
||||
{
|
||||
"serverId": 2,
|
||||
"/system/logging": true,
|
||||
"/ip/ipsec/identity": true,
|
||||
"/ip/ipsec/peer": true,
|
||||
"/ip/ipsec/policy": true,
|
||||
"/ip/ipsec/policy/group": true,
|
||||
"/ip/ipsec/mode-config": true,
|
||||
"/ip/ipsec/proposal": true,
|
||||
"/ip/ipsec/profile": true,
|
||||
"/certificate": true,
|
||||
"/file": true,
|
||||
"/ip/address": true,
|
||||
"/ip/route": true,
|
||||
"/ip/firewall/nat": true
|
||||
}
|
||||
],
|
||||
"databaseWrites": false,
|
||||
"certificate": {
|
||||
"name": "ipsec-user-mm-ipsec112-1791601534901",
|
||||
"common-name": "mm-ipsec112-1791601534901",
|
||||
"ca": "mm-ipsec112-1791601534901-ca",
|
||||
"key-usage": "digital-signature,key-encipherment,tls-client"
|
||||
},
|
||||
"certificates": [
|
||||
[
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901-ca",
|
||||
"trusted": "true",
|
||||
"trust-store": "all",
|
||||
"invalid-before": "2026-10-10 06:05:35",
|
||||
"invalid-after": "2026-10-12 06:05:35",
|
||||
"common-name": "mm-ipsec112-1791601534901-CA"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901-server",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791601534901-ca",
|
||||
"invalid-before": "2026-10-10 06:05:36",
|
||||
"invalid-after": "2026-10-12 06:05:36",
|
||||
"common-name": "194.226.121.150"
|
||||
},
|
||||
{
|
||||
"name": "ipsec-user-mm-ipsec112-1791601534901",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791601534901-ca",
|
||||
"invalid-before": "2026-10-10 06:05:36",
|
||||
"invalid-after": "2026-10-12 06:05:36",
|
||||
"common-name": "mm-ipsec112-1791601534901"
|
||||
},
|
||||
{
|
||||
"name": "ipsec-user-mm-ipsec112-1791601534901-decoy",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791601534901-ca",
|
||||
"invalid-before": "2026-10-10 06:05:37",
|
||||
"invalid-after": "2026-10-12 06:05:37",
|
||||
"common-name": "CN=mm-ipsec112-1791601534901"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901-client-imported",
|
||||
"trusted": "true",
|
||||
"trust-store": "ipsec",
|
||||
"invalid-before": "2026-10-10 05:05:36",
|
||||
"invalid-after": "2026-10-12 05:05:36",
|
||||
"common-name": "mm-ipsec112-1791601534901"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901-ca-imported",
|
||||
"trusted": "true",
|
||||
"trust-store": "ipsec",
|
||||
"invalid-before": "2026-10-10 05:05:35",
|
||||
"invalid-after": "2026-10-12 05:05:35",
|
||||
"common-name": "mm-ipsec112-1791601534901-CA"
|
||||
}
|
||||
]
|
||||
],
|
||||
"catalogCorrect": true,
|
||||
"dnPhase": {
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "CN=mm-ipsec112-1791601534901",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250",
|
||||
"remote-address": "104.165.244.7",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791601534901",
|
||||
"commonName": "CN=mm-ipsec112-1791601534901",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791601534901-decoy",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901",
|
||||
"commonName": "mm-ipsec112-1791601534901",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791601534901",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"decoyOnline": false
|
||||
},
|
||||
"fqdnPhase": {
|
||||
"configuredRemoteId": "fqdn:mm-ipsec112-1791601534901.example",
|
||||
"nativeId": "mm-ipsec112-1791601534901.example",
|
||||
"assignedAddress": "198.18.112.250",
|
||||
"originalOnline": true,
|
||||
"decoyOnline": false
|
||||
},
|
||||
"aliasName": "mm-ipsec112-1791601534901-psk",
|
||||
"aliasPhase": {
|
||||
"native": [
|
||||
{
|
||||
"id": "mm-ipsec112-1791601534901.example",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791601534901",
|
||||
"kind": "cert",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901",
|
||||
"kind": "cert",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791601534901-psk",
|
||||
"kind": "psk",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"clientsTotal": 3,
|
||||
"clientsOnline": 2
|
||||
}
|
||||
},
|
||||
"error": "One session still attributed to multiple configured clients"
|
||||
},
|
||||
"accepted": {
|
||||
"date": "2026-10-10",
|
||||
"block": "12.5.112",
|
||||
"name": "mm-ipsec112-1791602887310",
|
||||
"cn": "mm-ipsec112-1791602887310",
|
||||
"observations": [
|
||||
{
|
||||
"serverId": 1,
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "CN=mm-ipsec112-1791602887310",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250",
|
||||
"remote-address": "104.165.244.7",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"catalog": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791602887310",
|
||||
"commonName": "CN=mm-ipsec112-1791602887310",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602887310-decoy",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310",
|
||||
"commonName": "mm-ipsec112-1791602887310",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602887310",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"serverId": 2,
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "194.226.121.150",
|
||||
"state": "established",
|
||||
"remote-address": "194.226.121.150",
|
||||
"uptime": "0s"
|
||||
}
|
||||
],
|
||||
"catalog": []
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
{
|
||||
"serverId": 1,
|
||||
"/system/logging": true,
|
||||
"/ip/ipsec/identity": true,
|
||||
"/ip/ipsec/peer": true,
|
||||
"/ip/ipsec/policy": true,
|
||||
"/ip/ipsec/policy/group": true,
|
||||
"/ip/ipsec/mode-config": true,
|
||||
"/ip/ipsec/proposal": true,
|
||||
"/ip/ipsec/profile": true,
|
||||
"/certificate": true,
|
||||
"/file": true,
|
||||
"/ip/address": true,
|
||||
"/ip/route": true,
|
||||
"/ip/firewall/nat": true
|
||||
},
|
||||
{
|
||||
"serverId": 2,
|
||||
"/system/logging": true,
|
||||
"/ip/ipsec/identity": true,
|
||||
"/ip/ipsec/peer": true,
|
||||
"/ip/ipsec/policy": true,
|
||||
"/ip/ipsec/policy/group": true,
|
||||
"/ip/ipsec/mode-config": true,
|
||||
"/ip/ipsec/proposal": true,
|
||||
"/ip/ipsec/profile": true,
|
||||
"/certificate": true,
|
||||
"/file": true,
|
||||
"/ip/address": true,
|
||||
"/ip/route": true,
|
||||
"/ip/firewall/nat": true
|
||||
}
|
||||
],
|
||||
"databaseWrites": false,
|
||||
"certificate": {
|
||||
"name": "ipsec-user-mm-ipsec112-1791602887310",
|
||||
"common-name": "mm-ipsec112-1791602887310",
|
||||
"ca": "mm-ipsec112-1791602887310-ca",
|
||||
"key-usage": "digital-signature,key-encipherment,tls-client"
|
||||
},
|
||||
"certificates": [
|
||||
[
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310-ca",
|
||||
"trusted": "true",
|
||||
"trust-store": "all",
|
||||
"invalid-before": "2026-10-10 06:28:08",
|
||||
"invalid-after": "2026-10-12 06:28:08",
|
||||
"common-name": "mm-ipsec112-1791602887310-CA"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310-server",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791602887310-ca",
|
||||
"invalid-before": "2026-10-10 06:28:09",
|
||||
"invalid-after": "2026-10-12 06:28:09",
|
||||
"common-name": "194.226.121.150"
|
||||
},
|
||||
{
|
||||
"name": "ipsec-user-mm-ipsec112-1791602887310",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791602887310-ca",
|
||||
"invalid-before": "2026-10-10 06:28:10",
|
||||
"invalid-after": "2026-10-12 06:28:10",
|
||||
"common-name": "mm-ipsec112-1791602887310"
|
||||
},
|
||||
{
|
||||
"name": "ipsec-user-mm-ipsec112-1791602887310-decoy",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791602887310-ca",
|
||||
"invalid-before": "2026-10-10 06:28:10",
|
||||
"invalid-after": "2026-10-12 06:28:10",
|
||||
"common-name": "CN=mm-ipsec112-1791602887310"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310-client-imported",
|
||||
"trusted": "true",
|
||||
"trust-store": "ipsec",
|
||||
"invalid-before": "2026-10-10 05:28:10",
|
||||
"invalid-after": "2026-10-12 05:28:10",
|
||||
"common-name": "mm-ipsec112-1791602887310"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310-ca-imported",
|
||||
"trusted": "true",
|
||||
"trust-store": "ipsec",
|
||||
"invalid-before": "2026-10-10 05:28:08",
|
||||
"invalid-after": "2026-10-12 05:28:08",
|
||||
"common-name": "mm-ipsec112-1791602887310-CA"
|
||||
}
|
||||
]
|
||||
],
|
||||
"catalogCorrect": true,
|
||||
"dnPhase": {
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "CN=mm-ipsec112-1791602887310",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250",
|
||||
"remote-address": "104.165.244.7",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791602887310",
|
||||
"commonName": "CN=mm-ipsec112-1791602887310",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602887310-decoy",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310",
|
||||
"commonName": "mm-ipsec112-1791602887310",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602887310",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"decoyOnline": false
|
||||
},
|
||||
"fqdnPhase": {
|
||||
"configuredRemoteId": "fqdn:mm-ipsec112-1791602887310.example",
|
||||
"nativeId": "mm-ipsec112-1791602887310.example",
|
||||
"assignedAddress": "198.18.112.250",
|
||||
"originalOnline": true,
|
||||
"decoyOnline": false
|
||||
},
|
||||
"aliasName": "mm-ipsec112-1791602887310-psk",
|
||||
"aliasPhase": {
|
||||
"native": [
|
||||
{
|
||||
"id": "mm-ipsec112-1791602887310.example",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791602887310",
|
||||
"kind": "cert",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310",
|
||||
"kind": "cert",
|
||||
"online": false,
|
||||
"sessionAmbiguous": true
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602887310-psk",
|
||||
"kind": "psk",
|
||||
"online": false,
|
||||
"sessionAmbiguous": true
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"clientsTotal": 3,
|
||||
"clientsOnline": 0,
|
||||
"clientsSessionAmbiguous": 2
|
||||
}
|
||||
},
|
||||
"recovered": {
|
||||
"originalOnline": true,
|
||||
"sessionAmbiguous": false,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
},
|
||||
"preliminaryFrontendVersion": {
|
||||
"displayedVersion": "dev",
|
||||
"reason": "APP_VERSION was ignored by frontend Dockerfile; corrected NEXT_PUBLIC_APP_VERSION",
|
||||
"functionalBrowser": {
|
||||
"date": "2026-10-10",
|
||||
"runtime": {
|
||||
"backend": "ux-alias112",
|
||||
"frontend": "ux-alias112"
|
||||
},
|
||||
"httpMocks": false,
|
||||
"cases": [
|
||||
{
|
||||
"theme": "dark",
|
||||
"width": 1280,
|
||||
"rootThemeConfirmed": true,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
},
|
||||
{
|
||||
"theme": "dark",
|
||||
"width": 320,
|
||||
"rootThemeConfirmed": true,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
},
|
||||
{
|
||||
"theme": "light",
|
||||
"width": 1280,
|
||||
"rootThemeConfirmed": true,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
},
|
||||
{
|
||||
"theme": "light",
|
||||
"width": 320,
|
||||
"rootThemeConfirmed": true,
|
||||
"unconnectedCertificateOffline": true,
|
||||
"ambiguousClientsUnknown": true,
|
||||
"unknownOnlineCount": true,
|
||||
"reloadConfirmed": true,
|
||||
"noPageOverflow": true
|
||||
}
|
||||
],
|
||||
"pageErrors": [],
|
||||
"applicationWrites": [],
|
||||
"scope": "Real certificate/PSK alias ambiguity, unknown row statuses and online count, reload, desktop/mobile, two themes"
|
||||
},
|
||||
"native": {
|
||||
"date": "2026-10-10",
|
||||
"block": "12.5.112",
|
||||
"name": "mm-ipsec112-1791602069063",
|
||||
"cn": "mm-ipsec112-1791602069063",
|
||||
"observations": [
|
||||
{
|
||||
"serverId": 1,
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "CN=mm-ipsec112-1791602069063",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250",
|
||||
"remote-address": "104.165.244.7",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"catalog": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791602069063",
|
||||
"commonName": "CN=mm-ipsec112-1791602069063",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602069063-decoy",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063",
|
||||
"commonName": "mm-ipsec112-1791602069063",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602069063",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"serverId": 2,
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "194.226.121.150",
|
||||
"state": "established",
|
||||
"remote-address": "194.226.121.150",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"catalog": []
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
{
|
||||
"serverId": 1,
|
||||
"/system/logging": true,
|
||||
"/ip/ipsec/identity": true,
|
||||
"/ip/ipsec/peer": true,
|
||||
"/ip/ipsec/policy": true,
|
||||
"/ip/ipsec/policy/group": true,
|
||||
"/ip/ipsec/mode-config": true,
|
||||
"/ip/ipsec/proposal": true,
|
||||
"/ip/ipsec/profile": true,
|
||||
"/certificate": true,
|
||||
"/file": true,
|
||||
"/ip/address": true,
|
||||
"/ip/route": true,
|
||||
"/ip/firewall/nat": true
|
||||
},
|
||||
{
|
||||
"serverId": 2,
|
||||
"/system/logging": true,
|
||||
"/ip/ipsec/identity": true,
|
||||
"/ip/ipsec/peer": true,
|
||||
"/ip/ipsec/policy": true,
|
||||
"/ip/ipsec/policy/group": true,
|
||||
"/ip/ipsec/mode-config": true,
|
||||
"/ip/ipsec/proposal": true,
|
||||
"/ip/ipsec/profile": true,
|
||||
"/certificate": true,
|
||||
"/file": true,
|
||||
"/ip/address": true,
|
||||
"/ip/route": true,
|
||||
"/ip/firewall/nat": true
|
||||
}
|
||||
],
|
||||
"databaseWrites": false,
|
||||
"certificate": {
|
||||
"name": "ipsec-user-mm-ipsec112-1791602069063",
|
||||
"common-name": "mm-ipsec112-1791602069063",
|
||||
"ca": "mm-ipsec112-1791602069063-ca",
|
||||
"key-usage": "digital-signature,key-encipherment,tls-client"
|
||||
},
|
||||
"certificates": [
|
||||
[
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063-ca",
|
||||
"trusted": "true",
|
||||
"trust-store": "all",
|
||||
"invalid-before": "2026-10-10 06:14:30",
|
||||
"invalid-after": "2026-10-12 06:14:30",
|
||||
"common-name": "mm-ipsec112-1791602069063-CA"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063-server",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791602069063-ca",
|
||||
"invalid-before": "2026-10-10 06:14:32",
|
||||
"invalid-after": "2026-10-12 06:14:32",
|
||||
"common-name": "194.226.121.150"
|
||||
},
|
||||
{
|
||||
"name": "ipsec-user-mm-ipsec112-1791602069063",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791602069063-ca",
|
||||
"invalid-before": "2026-10-10 06:14:33",
|
||||
"invalid-after": "2026-10-12 06:14:33",
|
||||
"common-name": "mm-ipsec112-1791602069063"
|
||||
},
|
||||
{
|
||||
"name": "ipsec-user-mm-ipsec112-1791602069063-decoy",
|
||||
"trusted": "false",
|
||||
"trust-store": "all",
|
||||
"ca": "mm-ipsec112-1791602069063-ca",
|
||||
"invalid-before": "2026-10-10 06:14:34",
|
||||
"invalid-after": "2026-10-12 06:14:34",
|
||||
"common-name": "CN=mm-ipsec112-1791602069063"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063-client-imported",
|
||||
"trusted": "true",
|
||||
"trust-store": "ipsec",
|
||||
"invalid-before": "2026-10-10 05:14:33",
|
||||
"invalid-after": "2026-10-12 05:14:33",
|
||||
"common-name": "mm-ipsec112-1791602069063"
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063-ca-imported",
|
||||
"trusted": "true",
|
||||
"trust-store": "ipsec",
|
||||
"invalid-before": "2026-10-10 05:14:30",
|
||||
"invalid-after": "2026-10-12 05:14:30",
|
||||
"common-name": "mm-ipsec112-1791602069063-CA"
|
||||
}
|
||||
]
|
||||
],
|
||||
"catalogCorrect": true,
|
||||
"dnPhase": {
|
||||
"active": [
|
||||
{
|
||||
".id": "*1",
|
||||
"id": "CN=mm-ipsec112-1791602069063",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250",
|
||||
"remote-address": "104.165.244.7",
|
||||
"uptime": "1s"
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791602069063",
|
||||
"commonName": "CN=mm-ipsec112-1791602069063",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602069063-decoy",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063",
|
||||
"commonName": "mm-ipsec112-1791602069063",
|
||||
"certName": "ipsec-user-mm-ipsec112-1791602069063",
|
||||
"online": true,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"decoyOnline": false
|
||||
},
|
||||
"fqdnPhase": {
|
||||
"configuredRemoteId": "fqdn:mm-ipsec112-1791602069063.example",
|
||||
"nativeId": "mm-ipsec112-1791602069063.example",
|
||||
"assignedAddress": "198.18.112.250",
|
||||
"originalOnline": true,
|
||||
"decoyOnline": false
|
||||
},
|
||||
"aliasName": "mm-ipsec112-1791602069063-psk",
|
||||
"aliasPhase": {
|
||||
"native": [
|
||||
{
|
||||
"id": "mm-ipsec112-1791602069063.example",
|
||||
"state": "established",
|
||||
"dynamic-address": "198.18.112.250"
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"name": "CN=mm-ipsec112-1791602069063",
|
||||
"kind": "cert",
|
||||
"online": false
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063",
|
||||
"kind": "cert",
|
||||
"online": false,
|
||||
"sessionAmbiguous": true
|
||||
},
|
||||
{
|
||||
"name": "mm-ipsec112-1791602069063-psk",
|
||||
"kind": "psk",
|
||||
"online": false,
|
||||
"sessionAmbiguous": true
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"clientsTotal": 3,
|
||||
"clientsOnline": 0,
|
||||
"clientsSessionAmbiguous": 2
|
||||
}
|
||||
},
|
||||
"recovered": {
|
||||
"originalOnline": true,
|
||||
"sessionAmbiguous": false,
|
||||
"activeAddress": "198.18.112.250"
|
||||
}
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"ipsecStateChecks": 102,
|
||||
"profileScripts": 8,
|
||||
"uniqueE2eAccepted": 14,
|
||||
"enhancedServerCardCases": 2,
|
||||
"initialWebServerTimeout": true,
|
||||
"initialGeneratedNextTypesErrors": true,
|
||||
"sourceTypeScriptPassed": true,
|
||||
"generatedNextTypesExcluded": true,
|
||||
"productionTypeScriptPassed": true,
|
||||
"eslintPassed": true
|
||||
},
|
||||
"browserEvidence": "browser-ipsec-alias-2026-10-10.json",
|
||||
"deployment": {
|
||||
"backendImage": "sha256:03e110dd414b575ad9a8f13f7b0302f241dbd3e439418c8ad1bbca7dc1c6fc9c",
|
||||
"frontendImage": "sha256:4bf4cad8b3c990a7259f84cf27fd6bb9ee34e3db904223b559c0559dbbe094a2",
|
||||
"revisionLabel": "alias112",
|
||||
"health": {
|
||||
"status": "ok",
|
||||
"timestamp": "2026-10-10T03:19:59.783Z",
|
||||
"version": "1.0.0-test.alias112",
|
||||
"eventLoopDelayMs": 20,
|
||||
"flowWorker": {
|
||||
"alive": false,
|
||||
"bound": false,
|
||||
"pendingSize": 0,
|
||||
"dropped": 0,
|
||||
"packetsReceived": 0
|
||||
}
|
||||
},
|
||||
"contextHashes": {
|
||||
"backend": {
|
||||
"backend/src/services/ipsec-live.ts": "7f5cccea14c63e96aa9774beab28257a9a81d624cc15a7ef88d19e17e25d5fd2",
|
||||
"backend/src/services/ipsec-state.test.ts": "8a0f19b3a16962a2217ac76bfd4c1009813f59cf9e50a4b90fb31165ff6a9a6d",
|
||||
"packages/contracts/src/ipsec.ts": "17f9fdcd528fba5fc5df539ca4392bdcd98d99957b1273e83c51537efa1630e5"
|
||||
},
|
||||
"frontend": {
|
||||
"app/(main)/ipsec/page.tsx": "2673411a60fd1796389ddbb6cba37a16b607af87fceedfc37e89e18717fd013e",
|
||||
"components/ipsec/ipsec-users-grid.tsx": "75a4f4c7f66badbc425669114982fbd067121e93ecf7800e02b3c8da83d80cfe",
|
||||
"components/ipsec/ipsec-server-grid.tsx": "c48e55cb0e63c9b7ca55f6277b194aa748bc7b40982459cdb9c4fe331df68011",
|
||||
"packages/contracts/src/ipsec.ts": "17f9fdcd528fba5fc5df539ca4392bdcd98d99957b1273e83c51537efa1630e5"
|
||||
}
|
||||
},
|
||||
"frontendInitialImage": "sha256:0cf246b79dd054e5ecb4ce692d82badc3324211615fb9313aaa7b6dbfc2881f9",
|
||||
"frontendTag": "ux-alias112-version",
|
||||
"frontendVersion": "1.0.0-test.alias112"
|
||||
},
|
||||
"limits": [
|
||||
"Single observed session claimed by several visible catalog clients is marked unknown",
|
||||
"Duplicate native IDs and one certificate referenced by several identities remain separate acceptance bounds",
|
||||
"No new data-plane throughput, full PKI/restore, client OS or IPv6 claim"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -31,12 +31,16 @@ export const ipsecClientDtoSchema = z.object({
|
||||
modeConfigName: z.string().optional(),
|
||||
peerName: z.string().optional(),
|
||||
online: z.boolean(),
|
||||
/** One native session ID matches several clients; online/address are not confirmed. */
|
||||
sessionAmbiguous: z.boolean().optional(),
|
||||
activeAddress: z.string().optional(),
|
||||
activeSince: z.string().optional(),
|
||||
disabled: z.boolean(),
|
||||
comment: z.string().optional(),
|
||||
/** Создан менеджером (managed-комментарий). */
|
||||
managed: z.boolean(),
|
||||
}).refine(c => !c.sessionAmbiguous || (!c.online && !c.activeAddress && !c.activeSince), {
|
||||
message: "Неоднозначная сессия IPsec не может подтверждать online или активный адрес",
|
||||
})
|
||||
|
||||
/** Слушатель IKEv2 — /ip/ipsec/peer (passive). */
|
||||
@@ -115,6 +119,7 @@ export const ipsecServerSummaryDtoSchema = z.object({
|
||||
natRuleManaged: z.boolean(),
|
||||
clientsTotal: z.number().int().nonnegative(),
|
||||
clientsOnline: z.number().int().nonnegative(),
|
||||
clientsSessionAmbiguous: z.number().int().nonnegative().optional(),
|
||||
/** Все сертификаты роутера (managed + существующие). */
|
||||
certs: z.array(ipsecCertInfoDtoSchema).optional(),
|
||||
})
|
||||
|
||||
@@ -5,6 +5,44 @@ const client = (id: string, name = "Клиент " + id) => ({ id: id + "-*1", r
|
||||
const servers = [1, 2].map(id => ({ id, name: "Роутер " + id, host: "192.0.2." + id, enabled: true, country: "RU", type: "exit-node", status: "online" }))
|
||||
const full = { servers: [summary("1"), summary("2")], clients: [client("1"), client("2")] }
|
||||
|
||||
for (const width of [1280, 320]) {
|
||||
test(`IPsec: неоднозначная сессия и восстановление статуса ${width}px`, async ({ page }) => {
|
||||
await page.setViewportSize({ width, height: 1000 })
|
||||
let phase = 0
|
||||
const rows = [client("1", "Сертификат"), { ...client("1", "PSK"), id: "1-*2", rosId: "*2", kind: "psk", authMethod: "pre-shared-key" }]
|
||||
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
|
||||
await page.route("**/api/**", r => {
|
||||
const path = new URL(r.request().url()).pathname
|
||||
const values = phase === 0 ? rows.map(c => ({ ...c, sessionAmbiguous: true })) : [
|
||||
{ ...rows[0], online: true, activeAddress: "198.18.112.250", ...(phase === 2 ? { sessionAmbiguous: true } : {}) }, rows[1],
|
||||
]
|
||||
return r.fulfill({ json: path === "/api/ipsec" ? { servers: [{ ...summary("1"), clientsTotal: 2, clientsOnline: phase === 0 ? 0 : 1, ...(phase === 0 ? { clientsSessionAmbiguous: 2 } : {}) }], clients: values }
|
||||
: path === "/api/servers" ? servers : path === "/api/auth/config" ? { required: false } : {} })
|
||||
})
|
||||
await page.goto("/ipsec?server=1")
|
||||
const gridRows = page.locator("tr[data-row-id]")
|
||||
const ambiguity = page.getByRole("alert").filter({ hasText: "Статус части клиентов не определён" })
|
||||
await expect(ambiguity).toContainText("У 2 клиентов")
|
||||
await expect(gridRows).toHaveCount(2)
|
||||
await expect(gridRows.getByText("Не определено", { exact: true })).toHaveCount(2)
|
||||
await expect(gridRows.getByText("офлайн", { exact: true })).toHaveCount(0)
|
||||
await expect(page.getByLabel("Сводка IPsec")).toContainText("—")
|
||||
await page.getByRole("tab", { name: "Сервер", exact: true }).click()
|
||||
await expect(page.getByText("0 подтверждено онлайн / 2; статус 2 не определён", { exact: true })).toBeVisible()
|
||||
await page.getByRole("tab", { name: "Клиенты", exact: true }).click()
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
|
||||
phase = 1
|
||||
await page.getByRole("button", { name: "Обновить", exact: true }).click()
|
||||
await expect(ambiguity).toHaveCount(0)
|
||||
await expect(gridRows.getByText("офлайн", { exact: true })).toHaveCount(1)
|
||||
await expect(gridRows.getByText("198.18.112.250", { exact: true })).toHaveCount(1)
|
||||
phase = 2
|
||||
await page.getByRole("button", { name: "Обновить", exact: true }).click()
|
||||
await expect(page.getByRole("alert").filter({ hasText: "Не удалось загрузить IPsec" })).toBeVisible()
|
||||
await expect(gridRows.getByText("198.18.112.250", { exact: true })).toHaveCount(1)
|
||||
})
|
||||
}
|
||||
|
||||
for (const broken of ["http", "payload", "duplicate", "conflict", "peer-context", "pool-context", "blank-failure"]) {
|
||||
test(`IPsec: неизвестное начало и сохранение данных при ${broken}`, async ({ page }) => {
|
||||
let phase = 0
|
||||
|
||||
Reference in new issue
Block a user