diff --git a/backend/src/services/ipsec-certificate-dn.ts b/backend/src/services/ipsec-certificate-dn.ts new file mode 100644 index 00000000..2517f463 --- /dev/null +++ b/backend/src/services/ipsec-certificate-dn.ts @@ -0,0 +1,18 @@ +/** RouterOS active-peers.id uses the certificate subject in this field order. + * Values are printed verbatim, including commas/plus signs, so parsing the ID + * or matching a CN substring would misidentify subjects. Compare the complete + * rendered subject and reject collisions in the caller instead. + */ +export function routerOsCertificateDn(cert: Record): string | undefined { + const fields = [["C", "country"], ["S", "state"], ["L", "locality"], + ["O", "organization"], ["OU", "unit"], ["CN", "common-name"]] as const + if (!cert["common-name"]) return undefined + const parts: string[] = [] + for (const [attribute, field] of fields) { + const value = cert[field] + if (value === undefined || value === "") continue + if (typeof value !== "string" || /[\u0000\r\n]/.test(value)) return undefined + parts.push(`${attribute}=${value}`) + } + return parts.join(", ") +} diff --git a/backend/src/services/ipsec-live.ts b/backend/src/services/ipsec-live.ts index 22bfe967..7c5ece9f 100644 --- a/backend/src/services/ipsec-live.ts +++ b/backend/src/services/ipsec-live.ts @@ -28,6 +28,7 @@ import { selectSharedIke2Identity, } from "./ipsec-config.js" import { certificateRole, type CertificateRoleContext } from "./certificate-parse.js" +import { routerOsCertificateDn } from "./ipsec-certificate-dn.js" import { canonicalIpsecSnapshot, type IpsecLiveIdentity, @@ -248,10 +249,24 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] { const sharedRosId = shared?.[".id"] ? String(shared[".id"]) : undefined const activeByRemote = new Map() + const ambiguousRemoteIds = new Set() for (const a of state.active) { if (a.state !== "established") continue const rid = String(a.id ?? a["remote-id"] ?? "").trim() - if (rid) activeByRemote.set(rid, a) + if (rid) { + if (activeByRemote.has(rid)) ambiguousRemoteIds.add(rid) + else activeByRemote.set(rid, a) + } + } + for (const rid of ambiguousRemoteIds) activeByRemote.delete(rid) + + const subjectCounts = new Map() + const cnCounts = new Map() + for (const cert of state.certs) { + const subject = routerOsCertificateDn(cert) + if (subject) subjectCounts.set(subject, (subjectCounts.get(subject) ?? 0) + 1) + const cn = cert["common-name"] + if (cn) cnCounts.set(cn, (cnCounts.get(cn) ?? 0) + 1) } // RouterOS 7 active-peers.id contains the received value without its configured type prefix. @@ -286,10 +301,10 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] { const comment = identity?.comment ?? "" const mcName = (identity?.["mode-config"] ?? "").trim() const cn = String(cert["common-name"] ?? "").trim() - // Our issued certificates have a single CN subject; match the whole DN, never a CN substring. - const singleCn = cn && !/[,+=<>;\\"\u0000]/.test(cn) && state.certs.filter(c => c["common-name"] === cn).length === 1 - ? activeByRemote.get(`CN=${cn}`) : undefined - const active = (cn ? findActive(cn) : undefined) ?? singleCn + const subject = routerOsCertificateDn(cert) + const bySubject = subject && subjectCounts.get(subject) === 1 ? activeByRemote.get(subject) : undefined + const uniqueCn = cn && cnCounts.get(cn) === 1 + const active = (uniqueCn ? findActive(cn) : undefined) ?? bySubject ?? (identity?.["remote-id"] ? findActive(String(identity["remote-id"]).trim()) : undefined) out.push({ id: `${server.id}:${identity ? "identity" : "cert"}:${String(identity?.[".id"] ?? cert[".id"] ?? certName)}`, diff --git a/backend/src/services/ipsec-state.test.ts b/backend/src/services/ipsec-state.test.ts index 4543ccfb..4c057db7 100644 --- a/backend/src/services/ipsec-state.test.ts +++ b/backend/src/services/ipsec-state.test.ts @@ -99,4 +99,34 @@ assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false state.active[0]!.id = "CN=Original CN" state.certs.push({ ".id": "*DUPCN", name: "duplicate-cn", "common-name": "Original CN", ca: "ca", "key-usage": "tls-client" }) assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false); checks++ +state.certs = state.certs.filter(c => c[".id"] !== "*DUPCN") +const certificate = state.certs.find(c => c.name === "client")! +Object.assign(certificate, { country: "US", organization: "Example, Ltd", unit: "QA+Operations", "common-name": 'QA, Team+VPN="client"\\Lab' }) +state.active[0]!.id = 'C=US, O=Example, Ltd, OU=QA+Operations, CN=QA, Team+VPN="client"\\Lab' +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, true); checks++ +assert.equal(mapClients(state).find(c => c.certName === "client")?.activeAddress, "198.18.79.250"); checks++ +state.active[0]!.id += ", O=Other" +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false); checks++ +state.active[0]!.id = 'C=US, O=Example, Ltd, OU=QA+Operations, CN=QA, Team+VPN="client"\\Lab' +// An exact duplicate subject must never be attributed to either certificate. +state.certs.push({ ...certificate, ".id": "*DUPSUBJECT", name: "duplicate-subject" }) +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false); checks++ +state.certs = state.certs.filter(c => c[".id"] !== "*DUPSUBJECT") +// Different attribute tuples can have the same unescaped RouterOS rendering. +Object.assign(certificate, { organization: "Example, OU=QA", unit: "Ops" }) +state.active[0]!.id = 'C=US, O=Example, OU=QA, OU=Ops, CN=QA, Team+VPN="client"\\Lab' +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, true); checks++ +state.certs.push({ ...certificate, ".id": "*AMBIGUOUS", name: "ambiguous-subject", organization: "Example", unit: "QA, OU=Ops" }) +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false); checks++ +state.certs = state.certs.filter(c => c[".id"] !== "*AMBIGUOUS") +Object.assign(certificate, { organization: "Example, Ltd", unit: "QA+Operations" }) +state.active[0]!.id = 'C=US, O=Example, Ltd, OU=QA+Operations, CN=QA, Team+VPN="client"\\Lab' +state.active.push({ ...state.active[0]!, ".id": "*DUPSESSION", "dynamic-address": "198.18.79.251" }) +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false); checks++ +state.active.pop() +Object.assign(certificate, { state: "New York", locality: "Albany" }) +state.active[0]!.id = 'C=US, S=New York, L=Albany, O=Example, Ltd, OU=QA+Operations, CN=QA, Team+VPN="client"\\Lab' +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, true); checks++ +certificate.organization = "bad\nsubject" +assert.equal(mapClients(state).find(c => c.certName === "client")?.online, false); checks++ console.log(`ipsec-state: ${checks} checks passed`) diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index 1c10b3a2..f389d937 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -1,6 +1,6 @@ # UX/UI: протокол внешней приёмки 12.5 -Актуальное продолжение 2026-10-10: завершены12.5.107–109 — VXLAN bridge/FDB и IPv6 ULA inner в VXLAN/GRE/WireGuard по IPv4 outer. Steady/recovery Ping10/10 в обе стороны каждого типа; initial loss сохранён. Cleanup собственных объектов/baseline passed, обаCHR доступны. Runtime ux-patch102/ux-a11y101 прежний. Native IPv6 не означает поддержку IPv6 interface address в API/history/export GRE/WG. Следующий110 — профильная приёмка IPsec со сложным DN; Portal/Telegram ожидают настройки/разрешения.12.5 открыт. +Актуальное продолжение 2026-10-10: завершён12.5.110 — исправлено сопоставление сертификатного IPsec по полному DN (C/S/L/O/OU/CN, специальные символы), неоднозначные rendered subjects/active IDs не подтверждают online. Backend ux-dn110/version1.0.0-test.dn110, frontend ux-a11y101 прежний. State89/89, профильный IPsec/build/lint, live UI4/4 с проверкой actual theme; native established/assigned IP/catalog online и cleanup13 коллекций×2 passed. Все предварительные ошибки сохранены. Следующий111 — нестандартные IKE ID/границы сопоставления сертификатов; внешние 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). @@ -1058,3 +1058,19 @@ Initial результаты: gre/CHR1=0/3, gre/CHR2=1/3, wireguard/CHR1=3/3, wi Production aggregate GET /api/gre/tunnels и /api/wireguard вернули собственные интерфейсы без failures; WG allowedIps сохранил native IPv6 /128, privateKey не возвращён. Ограничение обнаружено и зафиксировано: CHR1: GRE localInnerIp="", WG address=null; CHR2: GRE localInnerIp="", WG address=null. Текущие GRE/WG readers получают interface addresses из /ip/address, поэтому native IPv6 адрес не попадает в это поле. Эти проверки не принимают IPv6 создание/restore/history/export через приложение и не расширяют его API. Поддержка полного IPv6 управления требует отдельной согласованной модели адресов и миграции snapshots. Перед очисткой exact IDs/markers и immutable reference fields сверены; собственные peers/IPv6 addresses/interfaces удалены. Baseline projection13 коллекций×2 и7 исходных параметров IPv6 settings совпали. Пароли прежние, оба CHR доступны. DB/runtime/исходники продукта не менялись, повтор build/общей UI регрессии не требовался. Открыты IPv6 outer/client OS/scale, application IPv6 address lifecycle и остальные пункты матрицы. Следующий110 — IPsec complex/escaped DN с собственной сертификатной парой и контролем online identity; внешние Portal/Telegram требуют настоящей настройки. + +## 12.5.110 — IPsec: полный DN сертификата и достоверный online (2026-10-10) + +Исправлена реальная ошибка: собственная IKEv2 certificate сессия на двух CHR7.24.5 established/получила198.18.110.250, но production каталог показывал клиента online=false. Сначала воспроизведён DN с country/organization/unit и comma/plus/equals вCN; затем полный subject с state/locality/кавычками/обратным слешем. RouterOS печатает строку без экранирования: C=US, S=New York, L=Albany, O=Example, Ltd, OU=QA+Operations, CN=... Поэтому не используется CN substring или общий RFC4514 parser. Новый ipsec-certificate-dn.ts строит точную полную строку из известных метаданных; ipsec-live.ts сравнивает весь subject, считает collisions по rendered string, не выбирает одну из одинаковых active IDs и требует уникальный CN для прежнего bare-CN fallback. Подсчёт subject/CN выполняется один раз на снимок. Выбор matched identity, сетевые операции, PKI, секреты, API DTO и UI-компоненты не менялись. + +Проверки: профильный test:ipsec (8 скриптов) passed; финальный state набор89/89, включая иной organization, одинаковые сертификаты, разные attribute tuples с одинаковой неэкранированной строкой, duplicate active ID и control characters. Backend/contracts production TypeScript build, ESLint трёх изменённых файлов и diff check passed. [Source manifest](ux-ui/acceptance/ipsec-dn-source-2026-10-10.json): base audited build-patch102 context +3 working-file overrides отHEAD1d61b50; context hashes3/3 и runtime compiled byte hashes2/2 совпали. Это не полный повтор audit всех production inputs. Docker backend ux-dn110/version1.0.0-test.dn110, imagesha256:f0cd7afc7391ac463c8b3c7d183b0c294f01ffca6beda3d240d26bec59c06d72, label dn110 — stage marker, неGitSHA. Entrypoint/node check и pg_restore18.6 passed; приватный pre-dn110.env сохранён, прежний backend image остаётся для rollback. Backend/PG healthy; frontend ux-a11y101 unchanged/HTTP browser passed. + +[Полный протокол](ux-ui/acceptance/ipsec-certificate-dn-2026-10-10.json) сохраняет7 preliminary native failures: два неподдерживаемых параметра fixture (comment вprofile и address-prefix), затем auth failures сложного/простого control. Причина тестовой конфигурации выявлена по my auth size0: import присвоил client иCA одинаковое имя. Их переименование по exactIDs в разные имена восстановило handshake; исправление trust собственногоCA/source address само по себе не устраняло дублирование. Все preliminary cleanups passed. Эти отказы не приписаны продукту и не заменены успешным итогом. Два успешных native before-fix воспроизведения доказывают именно ошибку online. После deploy полныйDN established, native lease и application online/activeAddress совпали. + +[Live UI4/4](ux-ui/acceptance/browser-ipsec-dn-2026-10-10.json):1280/320px×dark/light, URL выбранногоCHR, правильный online address, reload, page overflow0/JS errors0/application writes0. Первый помощник неверно использовал storage key theme; его4 cases не принимаются как две темы. В повторе возник detached read-only locator при refresh; helper ограниченно заново находит элемент, никакие mutations не повторяет. Финальный запуск использует rl-theme и проверяет root class; скриншоты actual dark/light сохранены, два размера/темы просмотрены. Frontend/shared ReUI/Frame/base-nova не менялись, общая UI регрессия не повторялась. + +Собственные CA/server/client certificates, импортированные сертификаты, peer/identity/profile/proposal/group/template/mode-config, export/upload files и временные logging rules удалены после exact-ID/name/comment/prefix preflight. Baseline13 коллекций×2 совпал, включая logging/certificates/files/IP/routes/NAT; default/metadata/public routes и исходный195.195.195.195/32CHR2 сохранялись. Private P12/PEM/pass files удалены из helper-каталога, private keys/пароли не записаны в репозиторий. В приложении использовался aggregate GET /api/ipsec без observed revision write; tests DB не меняли. ОбаCHR и SSH доступны, пароли не менялись. + +Границы: это сопоставление подтверждённой native сессии для данного формата RouterOS7.24.5, не общая DN/ASN.1 библиотека и не новая проверка encrypted data plane (77–82 остаются источником). Custom OIDs/другие форматы и IKE ID namespaces, клиентские ОС, полнаяPKI/policy-profile-proposal restore/IPv6/scale открыты. При неоднозначном rendered subject адрес не приписывается одному из клиентов. Следующий111 — нестандартные IKE ID и границы сопоставления сертификатных сессий; внешние интеграции всё ещё требуют настройки. Квота после live-блока: использовано33% пятичасового/67% недельного (значение до финальной записи). + +Референс семантики certificate ID: [официальная документация MikroTik IPsec](https://help.mikrotik.com/docs/spaces/ROS/pages/11993097/IPsec); фактический формат S/порядок/символы подтверждён native отчётом выше. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 594ed5cf..ee5ce07d 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-10: завершены12.5.107–109 — VXLAN bridge/FDB и IPv6 ULA inner в VXLAN/GRE/WireGuard по IPv4 outer. Steady/recovery Ping10/10 в обе стороны каждого типа; initial loss сохранён. Cleanup собственных объектов/baseline passed, обаCHR доступны. Runtime ux-patch102/ux-a11y101 прежний. Native IPv6 не означает поддержку IPv6 interface address в API/history/export GRE/WG. Следующий110 — профильная приёмка IPsec со сложным DN; Portal/Telegram ожидают настройки/разрешения.12.5 открыт. +Актуальное продолжение 2026-10-10: завершён12.5.110 — исправлено сопоставление сертификатного IPsec по полному DN (C/S/L/O/OU/CN, специальные символы), неоднозначные rendered subjects/active IDs не подтверждают online. Backend ux-dn110/version1.0.0-test.dn110, frontend ux-a11y101 прежний. State89/89, профильный IPsec/build/lint, live UI4/4 с проверкой actual theme; native established/assigned IP/catalog online и cleanup13 коллекций×2 passed. Все предварительные ошибки сохранены. Следующий111 — нестандартные IKE ID/границы сопоставления сертификатов; внешние Portal/Telegram требуют настройки и разрешения.12.5 открыт. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-10 -Актуальное продолжение 2026-10-10: завершены12.5.107–109 — VXLAN bridge/FDB и IPv6 ULA inner в VXLAN/GRE/WireGuard по IPv4 outer. Steady/recovery Ping10/10 в обе стороны каждого типа; initial loss сохранён. Cleanup собственных объектов/baseline passed, обаCHR доступны. Runtime ux-patch102/ux-a11y101 прежний. Native IPv6 не означает поддержку IPv6 interface address в API/history/export GRE/WG. Следующий110 — профильная приёмка IPsec со сложным DN; Portal/Telegram ожидают настройки/разрешения.12.5 открыт. +Актуальное продолжение 2026-10-10: завершён12.5.110 — исправлено сопоставление сертификатного IPsec по полному DN (C/S/L/O/OU/CN, специальные символы), неоднозначные rendered subjects/active IDs не подтверждают online. Backend ux-dn110/version1.0.0-test.dn110, frontend ux-a11y101 прежний. State89/89, профильный IPsec/build/lint, live UI4/4 с проверкой actual theme; native established/assigned IP/catalog online и cleanup13 коллекций×2 passed. Все предварительные ошибки сохранены. Следующий111 — нестандартные IKE ID/границы сопоставления сертификатов; внешние Portal/Telegram требуют настройки и разрешения.12.5 открыт. Этапы0–11 завершены в локальных границах журнала. История выполненных внешних блоков и доказательства сохранены в [журнале](ux-ui-stage-12.md) и [протоколе](ux-ui-external-acceptance.md). Реальная Telegram доставка, Portal SSO, multi-instance и оставшиеся профильные сетевые ограничения открыты. diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 5219b3cb..f34c00ed 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-10: завершены12.5.107–109 — VXLAN bridge/FDB и IPv6 ULA inner в VXLAN/GRE/WireGuard по IPv4 outer. Steady/recovery Ping10/10 в обе стороны каждого типа; initial loss сохранён. Cleanup собственных объектов/baseline passed, обаCHR доступны. Runtime ux-patch102/ux-a11y101 прежний. Native IPv6 не означает поддержку IPv6 interface address в API/history/export GRE/WG. Следующий110 — профильная приёмка IPsec со сложным DN; Portal/Telegram ожидают настройки/разрешения.12.5 открыт. +Актуальное продолжение 2026-10-10: завершён12.5.110 — исправлено сопоставление сертификатного IPsec по полному DN (C/S/L/O/OU/CN, специальные символы), неоднозначные rendered subjects/active IDs не подтверждают online. Backend ux-dn110/version1.0.0-test.dn110, frontend ux-a11y101 прежний. State89/89, профильный IPsec/build/lint, live UI4/4 с проверкой actual theme; native established/assigned IP/catalog online и cleanup13 коллекций×2 passed. Все предварительные ошибки сохранены. Следующий111 — нестандартные IKE ID/границы сопоставления сертификатов; внешние Portal/Telegram требуют настройки и разрешения.12.5 открыт. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -36,7 +36,23 @@ | 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–109 и ограничения ниже. Runtime backend ux-patch102/frontend ux-a11y101. | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–110 и ограничения ниже. Runtime backend ux-dn110/frontend ux-a11y101. | + +## 12.5.110 — IPsec: полный DN сертификата и достоверный online (2026-10-10) + +Исправлена реальная ошибка: собственная IKEv2 certificate сессия на двух CHR7.24.5 established/получила198.18.110.250, но production каталог показывал клиента online=false. Сначала воспроизведён DN с country/organization/unit и comma/plus/equals вCN; затем полный subject с state/locality/кавычками/обратным слешем. RouterOS печатает строку без экранирования: C=US, S=New York, L=Albany, O=Example, Ltd, OU=QA+Operations, CN=... Поэтому не используется CN substring или общий RFC4514 parser. Новый ipsec-certificate-dn.ts строит точную полную строку из известных метаданных; ipsec-live.ts сравнивает весь subject, считает collisions по rendered string, не выбирает одну из одинаковых active IDs и требует уникальный CN для прежнего bare-CN fallback. Подсчёт subject/CN выполняется один раз на снимок. Выбор matched identity, сетевые операции, PKI, секреты, API DTO и UI-компоненты не менялись. + +Проверки: профильный test:ipsec (8 скриптов) passed; финальный state набор89/89, включая иной organization, одинаковые сертификаты, разные attribute tuples с одинаковой неэкранированной строкой, duplicate active ID и control characters. Backend/contracts production TypeScript build, ESLint трёх изменённых файлов и diff check passed. [Source manifest](ux-ui/acceptance/ipsec-dn-source-2026-10-10.json): base audited build-patch102 context +3 working-file overrides отHEAD1d61b50; context hashes3/3 и runtime compiled byte hashes2/2 совпали. Это не полный повтор audit всех production inputs. Docker backend ux-dn110/version1.0.0-test.dn110, imagesha256:f0cd7afc7391ac463c8b3c7d183b0c294f01ffca6beda3d240d26bec59c06d72, label dn110 — stage marker, неGitSHA. Entrypoint/node check и pg_restore18.6 passed; приватный pre-dn110.env сохранён, прежний backend image остаётся для rollback. Backend/PG healthy; frontend ux-a11y101 unchanged/HTTP browser passed. + +[Полный протокол](ux-ui/acceptance/ipsec-certificate-dn-2026-10-10.json) сохраняет7 preliminary native failures: два неподдерживаемых параметра fixture (comment вprofile и address-prefix), затем auth failures сложного/простого control. Причина тестовой конфигурации выявлена по my auth size0: import присвоил client иCA одинаковое имя. Их переименование по exactIDs в разные имена восстановило handshake; исправление trust собственногоCA/source address само по себе не устраняло дублирование. Все preliminary cleanups passed. Эти отказы не приписаны продукту и не заменены успешным итогом. Два успешных native before-fix воспроизведения доказывают именно ошибку online. После deploy полныйDN established, native lease и application online/activeAddress совпали. + +[Live UI4/4](ux-ui/acceptance/browser-ipsec-dn-2026-10-10.json):1280/320px×dark/light, URL выбранногоCHR, правильный online address, reload, page overflow0/JS errors0/application writes0. Первый помощник неверно использовал storage key theme; его4 cases не принимаются как две темы. В повторе возник detached read-only locator при refresh; helper ограниченно заново находит элемент, никакие mutations не повторяет. Финальный запуск использует rl-theme и проверяет root class; скриншоты actual dark/light сохранены, два размера/темы просмотрены. Frontend/shared ReUI/Frame/base-nova не менялись, общая UI регрессия не повторялась. + +Собственные CA/server/client certificates, импортированные сертификаты, peer/identity/profile/proposal/group/template/mode-config, export/upload files и временные logging rules удалены после exact-ID/name/comment/prefix preflight. Baseline13 коллекций×2 совпал, включая logging/certificates/files/IP/routes/NAT; default/metadata/public routes и исходный195.195.195.195/32CHR2 сохранялись. Private P12/PEM/pass files удалены из helper-каталога, private keys/пароли не записаны в репозиторий. В приложении использовался aggregate GET /api/ipsec без observed revision write; tests DB не меняли. ОбаCHR и SSH доступны, пароли не менялись. + +Границы: это сопоставление подтверждённой native сессии для данного формата RouterOS7.24.5, не общая DN/ASN.1 библиотека и не новая проверка encrypted data plane (77–82 остаются источником). Custom OIDs/другие форматы и IKE ID namespaces, клиентские ОС, полнаяPKI/policy-profile-proposal restore/IPv6/scale открыты. При неоднозначном rendered subject адрес не приписывается одному из клиентов. Следующий111 — нестандартные IKE ID и границы сопоставления сертификатных сессий; внешние интеграции всё ещё требуют настройки. Квота после live-блока: использовано33% пятичасового/67% недельного (значение до финальной записи). + +Референс семантики certificate ID: [официальная документация MikroTik IPsec](https://help.mikrotik.com/docs/spaces/ROS/pages/11993097/IPsec); фактический формат S/порядок/символы подтверждён native отчётом выше. ## 12.5.109 — GRE/WireGuard: IPv6 inner и раздельное восстановление (2026-10-10) diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index 419772d3..cac9b206 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,8 +1,8 @@ # Оставшаяся внешняя приёмка — 2026-10-10 -Это актуальная матрица после 12.5.109. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. +Это актуальная матрица после 12.5.110. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. -Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-patch102`, frontend `ux-a11y101`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты109 удалены, исходные13 коллекций×2 и7 параметров IPv6 settings проверены; пароли не менялись. +Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-dn110`, frontend `ux-a11y101`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты110 удалены, исходные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 | Клиентские Windows/macOS/iOS/Android, сложные/escaped DN, полная 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 | Клиентские 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 — IPsec complex/escaped DN. Реальные интеграции требуют тестовых доступов и отдельного разрешения на сообщение. +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 — нестандартные IKE ID/границы сопоставления. Реальные интеграции требуют тестовых доступов и отдельного разрешения на сообщение. 3. **Заключительный профильный контроль:** после последнего исправления собрать только затронутую часть, проверить её live и обновить матрицу. Общую регрессию выполнить один раз на согласованном runtime. 4. **Внешние зависимости:** Telegram/Portal/client OS/multi-WAN/scale проходят отдельную приёмку при наличии нужных аккаунтов, устройств и разрешений. Лабораторный результат двух CHR не закрывает их автоматически. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 51c291f5..577c8a24 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-10: завершены12.5.107–109 — VXLAN bridge/FDB и IPv6 ULA inner в VXLAN/GRE/WireGuard по IPv4 outer. Steady/recovery Ping10/10 в обе стороны каждого типа; initial loss сохранён. Cleanup собственных объектов/baseline passed, обаCHR доступны. Runtime ux-patch102/ux-a11y101 прежний. Native IPv6 не означает поддержку IPv6 interface address в API/history/export GRE/WG. Следующий110 — профильная приёмка IPsec со сложным DN; Portal/Telegram ожидают настройки/разрешения.12.5 открыт. +Актуальное продолжение 2026-10-10: завершён12.5.110 — исправлено сопоставление сертификатного IPsec по полному DN (C/S/L/O/OU/CN, специальные символы), неоднозначные rendered subjects/active IDs не подтверждают online. Backend ux-dn110/version1.0.0-test.dn110, frontend ux-a11y101 прежний. State89/89, профильный IPsec/build/lint, live UI4/4 с проверкой actual theme; native established/assigned IP/catalog online и cleanup13 коллекций×2 passed. Все предварительные ошибки сохранены. Следующий111 — нестандартные IKE ID/границы сопоставления сертификатов; внешние Portal/Telegram требуют настройки и разрешения.12.5 открыт. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -2363,3 +2363,19 @@ Initial результаты: gre/CHR1=0/3, gre/CHR2=1/3, wireguard/CHR1=3/3, wi Production aggregate GET /api/gre/tunnels и /api/wireguard вернули собственные интерфейсы без failures; WG allowedIps сохранил native IPv6 /128, privateKey не возвращён. Ограничение обнаружено и зафиксировано: CHR1: GRE localInnerIp="", WG address=null; CHR2: GRE localInnerIp="", WG address=null. Текущие GRE/WG readers получают interface addresses из /ip/address, поэтому native IPv6 адрес не попадает в это поле. Эти проверки не принимают IPv6 создание/restore/history/export через приложение и не расширяют его API. Поддержка полного IPv6 управления требует отдельной согласованной модели адресов и миграции snapshots. Перед очисткой exact IDs/markers и immutable reference fields сверены; собственные peers/IPv6 addresses/interfaces удалены. Baseline projection13 коллекций×2 и7 исходных параметров IPv6 settings совпали. Пароли прежние, оба CHR доступны. DB/runtime/исходники продукта не менялись, повтор build/общей UI регрессии не требовался. Открыты IPv6 outer/client OS/scale, application IPv6 address lifecycle и остальные пункты матрицы. Следующий110 — IPsec complex/escaped DN с собственной сертификатной парой и контролем online identity; внешние Portal/Telegram требуют настоящей настройки. + +## 12.5.110 — IPsec: полный DN сертификата и достоверный online (2026-10-10) + +Исправлена реальная ошибка: собственная IKEv2 certificate сессия на двух CHR7.24.5 established/получила198.18.110.250, но production каталог показывал клиента online=false. Сначала воспроизведён DN с country/organization/unit и comma/plus/equals вCN; затем полный subject с state/locality/кавычками/обратным слешем. RouterOS печатает строку без экранирования: C=US, S=New York, L=Albany, O=Example, Ltd, OU=QA+Operations, CN=... Поэтому не используется CN substring или общий RFC4514 parser. Новый ipsec-certificate-dn.ts строит точную полную строку из известных метаданных; ipsec-live.ts сравнивает весь subject, считает collisions по rendered string, не выбирает одну из одинаковых active IDs и требует уникальный CN для прежнего bare-CN fallback. Подсчёт subject/CN выполняется один раз на снимок. Выбор matched identity, сетевые операции, PKI, секреты, API DTO и UI-компоненты не менялись. + +Проверки: профильный test:ipsec (8 скриптов) passed; финальный state набор89/89, включая иной organization, одинаковые сертификаты, разные attribute tuples с одинаковой неэкранированной строкой, duplicate active ID и control characters. Backend/contracts production TypeScript build, ESLint трёх изменённых файлов и diff check passed. [Source manifest](ux-ui/acceptance/ipsec-dn-source-2026-10-10.json): base audited build-patch102 context +3 working-file overrides отHEAD1d61b50; context hashes3/3 и runtime compiled byte hashes2/2 совпали. Это не полный повтор audit всех production inputs. Docker backend ux-dn110/version1.0.0-test.dn110, imagesha256:f0cd7afc7391ac463c8b3c7d183b0c294f01ffca6beda3d240d26bec59c06d72, label dn110 — stage marker, неGitSHA. Entrypoint/node check и pg_restore18.6 passed; приватный pre-dn110.env сохранён, прежний backend image остаётся для rollback. Backend/PG healthy; frontend ux-a11y101 unchanged/HTTP browser passed. + +[Полный протокол](ux-ui/acceptance/ipsec-certificate-dn-2026-10-10.json) сохраняет7 preliminary native failures: два неподдерживаемых параметра fixture (comment вprofile и address-prefix), затем auth failures сложного/простого control. Причина тестовой конфигурации выявлена по my auth size0: import присвоил client иCA одинаковое имя. Их переименование по exactIDs в разные имена восстановило handshake; исправление trust собственногоCA/source address само по себе не устраняло дублирование. Все preliminary cleanups passed. Эти отказы не приписаны продукту и не заменены успешным итогом. Два успешных native before-fix воспроизведения доказывают именно ошибку online. После deploy полныйDN established, native lease и application online/activeAddress совпали. + +[Live UI4/4](ux-ui/acceptance/browser-ipsec-dn-2026-10-10.json):1280/320px×dark/light, URL выбранногоCHR, правильный online address, reload, page overflow0/JS errors0/application writes0. Первый помощник неверно использовал storage key theme; его4 cases не принимаются как две темы. В повторе возник detached read-only locator при refresh; helper ограниченно заново находит элемент, никакие mutations не повторяет. Финальный запуск использует rl-theme и проверяет root class; скриншоты actual dark/light сохранены, два размера/темы просмотрены. Frontend/shared ReUI/Frame/base-nova не менялись, общая UI регрессия не повторялась. + +Собственные CA/server/client certificates, импортированные сертификаты, peer/identity/profile/proposal/group/template/mode-config, export/upload files и временные logging rules удалены после exact-ID/name/comment/prefix preflight. Baseline13 коллекций×2 совпал, включая logging/certificates/files/IP/routes/NAT; default/metadata/public routes и исходный195.195.195.195/32CHR2 сохранялись. Private P12/PEM/pass files удалены из helper-каталога, private keys/пароли не записаны в репозиторий. В приложении использовался aggregate GET /api/ipsec без observed revision write; tests DB не меняли. ОбаCHR и SSH доступны, пароли не менялись. + +Границы: это сопоставление подтверждённой native сессии для данного формата RouterOS7.24.5, не общая DN/ASN.1 библиотека и не новая проверка encrypted data plane (77–82 остаются источником). Custom OIDs/другие форматы и IKE ID namespaces, клиентские ОС, полнаяPKI/policy-profile-proposal restore/IPv6/scale открыты. При неоднозначном rendered subject адрес не приписывается одному из клиентов. Следующий111 — нестандартные IKE ID и границы сопоставления сертификатных сессий; внешние интеграции всё ещё требуют настройки. Квота после live-блока: использовано33% пятичасового/67% недельного (значение до финальной записи). + +Референс семантики certificate ID: [официальная документация MikroTik IPsec](https://help.mikrotik.com/docs/spaces/ROS/pages/11993097/IPsec); фактический формат S/порядок/символы подтверждён native отчётом выше. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 4a1192d8..17e763c9 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -1,6 +1,6 @@ # Тестовый сервер UX/UI — 2026-10-10 -Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-patch102/version1.0.0-test.patch102, frontend ux-a11y101/version1.0.0-test.a11y101; backend/PG healthy, frontend HTTP/browser passed. VPN107–109: VXLAN bridge/FDB и native IPv6 inner VXLAN/GRE/WireGuard приняты в границах журнала; собственные объекты удалены, baseline восстановлен; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние. +Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-dn110/version1.0.0-test.dn110, frontend ux-a11y101/version1.0.0-test.a11y101; backend/PG healthy, frontend HTTP/browser passed. VPN107–109 и IPsec110: bridge/FDB/IPv6 inner и исправление online по полному DN приняты в границах журнала; собственные объекты удалены, 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-patch102 и mmapp-test/frontend:ux-a11y101; запущены | +| Образы приложения | mmapp-test/backend:ux-dn110 и mmapp-test/frontend:ux-a11y101; запущены | Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example). diff --git a/docs/ux-ui/acceptance/browser-ipsec-dn-2026-10-10.json b/docs/ux-ui/acceptance/browser-ipsec-dn-2026-10-10.json new file mode 100644 index 00000000..277c1c5d --- /dev/null +++ b/docs/ux-ui/acceptance/browser-ipsec-dn-2026-10-10.json @@ -0,0 +1,45 @@ +{ + "date": "2026-10-10", + "runtime": { + "backend": "ux-dn110", + "frontend": "ux-a11y101" + }, + "httpMocks": false, + "cases": [ + { + "theme": "dark", + "width": 1280, + "rootThemeConfirmed": true, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + }, + { + "theme": "dark", + "width": 320, + "rootThemeConfirmed": true, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + }, + { + "theme": "light", + "width": 1280, + "rootThemeConfirmed": true, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + }, + { + "theme": "light", + "width": 320, + "rootThemeConfirmed": true, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + } + ], + "pageErrors": [], + "applicationWrites": [], + "scope": "Real established certificate DN client status/address, reload, desktop/mobile, two themes" +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/ipsec-certificate-dn-2026-10-10.json b/docs/ux-ui/acceptance/ipsec-certificate-dn-2026-10-10.json new file mode 100644 index 00000000..e5f10c07 --- /dev/null +++ b/docs/ux-ui/acceptance/ipsec-certificate-dn-2026-10-10.json @@ -0,0 +1,1291 @@ +{ + "date": "2026-10-10", + "block": "12.5.110", + "runtime": { + "backend": "ux-dn110", + "frontend": "ux-a11y101" + }, + "preliminaryNativeAttempts": [ + { + "file": "ipsec110-preliminary.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598221062", + "cn": "mm-ipsec110-1791598221062, QA+Team=VPN", + "observations": [], + "cleanup": [ + { + "serverId": 1, + "/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, + "/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-ipsec110-1791598221062", + "common-name": "mm-ipsec110-1791598221062, QA+Team=VPN", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "ca": "mm-ipsec110-1791598221062-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "error": "RouterOS API error 400 on /ip/ipsec/profile: {\"detail\":\"unknown parameter comment\",\"error\":400,\"message\":\"Bad Request\"}" + } + }, + { + "file": "ipsec110-preliminary2.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598289113", + "cn": "mm-ipsec110-1791598289113, QA+Team=VPN", + "observations": [], + "cleanup": [ + { + "serverId": 1, + "/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, + "/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-ipsec110-1791598289113", + "common-name": "mm-ipsec110-1791598289113, QA+Team=VPN", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "ca": "mm-ipsec110-1791598289113-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "error": "RouterOS API error 400 on /ip/ipsec/mode-config: {\"detail\":\"unknown parameter address-prefix\",\"error\":400,\"message\":\"Bad Request\"}" + } + }, + { + "file": "ipsec110-preliminary3.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598344406", + "cn": "mm-ipsec110-1791598344406, QA+Team=VPN", + "observations": [ + { + "serverId": 1, + "active": [], + "catalog": [ + { + "name": "mm-ipsec110-1791598344406", + "commonName": "mm-ipsec110-1791598344406, QA+Team=VPN", + "certName": "ipsec-user-mm-ipsec110-1791598344406", + "online": false + } + ] + }, + { + "serverId": 2, + "active": [], + "catalog": [] + } + ], + "cleanup": [ + { + "serverId": 1, + "/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, + "/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-ipsec110-1791598344406", + "common-name": "mm-ipsec110-1791598344406, QA+Team=VPN", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "ca": "mm-ipsec110-1791598344406-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "error": "Complex DN session not established" + } + }, + { + "file": "ipsec110-preliminary4.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598444189", + "cn": "mm-ipsec110-1791598444189, QA+Team=VPN", + "observations": [ + { + "serverId": 1, + "active": [], + "catalog": [ + { + "name": "mm-ipsec110-1791598444189", + "commonName": "mm-ipsec110-1791598444189, QA+Team=VPN", + "certName": "ipsec-user-mm-ipsec110-1791598444189", + "online": false + } + ] + }, + { + "serverId": 2, + "active": [], + "catalog": [] + } + ], + "cleanup": [ + { + "serverId": 1, + "/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, + "/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-ipsec110-1791598444189", + "common-name": "mm-ipsec110-1791598444189, QA+Team=VPN", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "ca": "mm-ipsec110-1791598444189-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "error": "Complex DN session not established" + } + }, + { + "file": "ipsec110-control.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598597230", + "cn": "mm-ipsec110-1791598597230", + "observations": [ + { + "serverId": 1, + "active": [], + "catalog": [ + { + "name": "mm-ipsec110-1791598597230", + "commonName": "mm-ipsec110-1791598597230", + "certName": "ipsec-user-mm-ipsec110-1791598597230", + "online": false + } + ] + }, + { + "serverId": 2, + "active": [], + "catalog": [] + } + ], + "cleanup": [ + { + "serverId": 1, + "/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, + "/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-ipsec110-1791598597230", + "common-name": "mm-ipsec110-1791598597230", + "ca": "mm-ipsec110-1791598597230-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "error": "Complex DN session not established" + } + }, + { + "file": "ipsec110-control-debug.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598765912", + "cn": "mm-ipsec110-1791598765912", + "observations": [ + { + "serverId": 1, + "active": [], + "catalog": [ + { + "name": "mm-ipsec110-1791598765912", + "commonName": "mm-ipsec110-1791598765912", + "certName": "ipsec-user-mm-ipsec110-1791598765912", + "online": false + } + ] + }, + { + "serverId": 2, + "active": [], + "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-ipsec110-1791598765912", + "common-name": "mm-ipsec110-1791598765912", + "ca": "mm-ipsec110-1791598765912-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "debug": [ + { + "time": "2026-10-10 05:19:26", + "message": "generated CA certificate: mm-ipsec110-1791598765912-ca" + }, + { + "time": "2026-10-10 05:19:28", + "message": "generated certificate 651A34B1F81F72A2:194.226.121.150::::::IP:194.226.121.150 rsa-size:2048 usage:80000005 valid:2 skid:29d6d9894d7634cbd887e32dc13d8ec690e9c9cb for CA mm-ipsec110-1791598765912-ca" + }, + { + "time": "2026-10-10 05:19:28", + "message": "generated certificate 40122BB473E50D37:mm-ipsec110-1791598765912::::: rsa-size:2048 usage:40000005 valid:2 skid:9fa06d40a5939e8046f4fdb68f2d04c05826cc5d for CA mm-ipsec110-1791598765912-ca" + }, + { + "time": "2026-10-10 05:19:30", + "message": "ipsec proposal mm-ipsec110-1791598765912 added by api:admin@:: (*1 = /ip ipsec proposal add auth-algorithms=sha256 enc-algorithms=aes-256-cbc name=mm-ipsec110-1791598765912 pfs-group=modp2048)" + } + ], + "error": "Complex DN session not established" + } + }, + { + "file": "ipsec110-control-diagnostic.json", + "report": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791598930518", + "cn": "mm-ipsec110-1791598930518", + "observations": [ + { + "serverId": 1, + "active": [], + "catalog": [ + { + "name": "mm-ipsec110-1791598930518", + "commonName": "mm-ipsec110-1791598930518", + "certName": "ipsec-user-mm-ipsec110-1791598930518", + "online": false + } + ] + }, + { + "serverId": 2, + "active": [], + "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-ipsec110-1791598930518", + "common-name": "mm-ipsec110-1791598930518", + "ca": "mm-ipsec110-1791598930518-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "debug": [ + [], + [ + { + "time": "2026-10-10 04:14:31", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:14:41", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:14:51", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:16:44", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:16:54", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:17:04", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:17:15", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:17:25", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:19:30", + "message": "initiator can't find identity for peer: mm-ipsec110-1791598765912" + }, + { + "time": "2026-10-10 04:19:41", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:19:51", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:22:17", + "message": "mm-ipsec110-1791598930518: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:22:17", + "message": "mm-ipsec110-1791598930518: => my auth (size 0x0)" + }, + { + "time": "2026-10-10 04:22:17", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:22:27", + "message": "mm-ipsec110-1791598930518: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:22:27", + "message": "mm-ipsec110-1791598930518: => my auth (size 0x0)" + }, + { + "time": "2026-10-10 04:22:27", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:22:37", + "message": "mm-ipsec110-1791598930518: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:22:37", + "message": "mm-ipsec110-1791598930518: => my auth (size 0x0)" + }, + { + "time": "2026-10-10 04:22:37", + "message": "got fatal error: AUTHENTICATION_FAILED" + } + ] + ], + "certificates": [ + [ + { + "name": "mm-ipsec110-1791598930518-ca", + "trusted": "true", + "trust-store": "all", + "invalid-before": "2026-10-10 05:22:12", + "invalid-after": "2026-10-12 05:22:12", + "common-name": "mm-ipsec110-1791598930518-CA" + }, + { + "name": "mm-ipsec110-1791598930518-server", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791598930518-ca", + "invalid-before": "2026-10-10 05:22:12", + "invalid-after": "2026-10-12 05:22:12", + "common-name": "194.226.121.150" + }, + { + "name": "ipsec-user-mm-ipsec110-1791598930518", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791598930518-ca", + "invalid-before": "2026-10-10 05:22:13", + "invalid-after": "2026-10-12 05:22:13", + "common-name": "mm-ipsec110-1791598930518" + } + ], + [ + { + "name": "mm-ipsec110-1791598930518-import", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:22:13", + "invalid-after": "2026-10-12 04:22:13", + "common-name": "mm-ipsec110-1791598930518" + }, + { + "name": "mm-ipsec110-1791598930518-import", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:22:12", + "invalid-after": "2026-10-12 04:22:12", + "common-name": "mm-ipsec110-1791598930518-CA" + } + ] + ], + "error": "Complex DN session not established" + } + } + ], + "beforeFix": { + "complex": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791599034879", + "cn": "mm-ipsec110-1791599034879, QA+Team=VPN", + "observations": [ + { + "serverId": 1, + "active": [ + { + ".id": "*1", + "id": "C=US, O=Example, Ltd, OU=QA+Operations, CN=mm-ipsec110-1791599034879, QA+Team=VPN", + "state": "established", + "dynamic-address": "198.18.110.250", + "remote-address": "104.165.244.7", + "uptime": "1s" + } + ], + "catalog": [ + { + "name": "mm-ipsec110-1791599034879", + "commonName": "mm-ipsec110-1791599034879, QA+Team=VPN", + "certName": "ipsec-user-mm-ipsec110-1791599034879", + "online": false + } + ] + }, + { + "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-ipsec110-1791599034879", + "common-name": "mm-ipsec110-1791599034879, QA+Team=VPN", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "ca": "mm-ipsec110-1791599034879-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "debug": [ + [ + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => certificate (size 0x381)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => peer's auth (size 0x100)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "peer authorized: mm-ipsec110-1791599034879 104.165.244.7-194.226.121.150 8b32523df8e1e6da:cefc293a7eb1e7fa" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => my auth (size 0x100)" + } + ], + [ + { + "time": "2026-10-10 04:22:17", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:22:27", + "message": "mm-ipsec110-1791598930518: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:22:27", + "message": "mm-ipsec110-1791598930518: => my auth (size 0x0)" + }, + { + "time": "2026-10-10 04:22:27", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:22:37", + "message": "mm-ipsec110-1791598930518: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:22:37", + "message": "mm-ipsec110-1791598930518: => my auth (size 0x0)" + }, + { + "time": "2026-10-10 04:22:37", + "message": "got fatal error: AUTHENTICATION_FAILED" + }, + { + "time": "2026-10-10 04:24:03", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:24:03", + "message": "mm-ipsec110-1791599034879: => my auth (size 0x100)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "mm-ipsec110-1791599034879: => certificate (size 0x33f)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "mm-ipsec110-1791599034879: => peer's auth (size 0x100)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "peer authorized: mm-ipsec110-1791599034879 104.165.244.7-194.226.121.150 8b32523df8e1e6da:cefc293a7eb1e7fa" + } + ] + ], + "certificates": [ + [ + { + "name": "mm-ipsec110-1791599034879-ca", + "trusted": "true", + "trust-store": "all", + "invalid-before": "2026-10-10 05:23:56", + "invalid-after": "2026-10-12 05:23:56", + "common-name": "mm-ipsec110-1791599034879-CA" + }, + { + "name": "mm-ipsec110-1791599034879-server", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791599034879-ca", + "invalid-before": "2026-10-10 05:23:58", + "invalid-after": "2026-10-12 05:23:58", + "common-name": "194.226.121.150" + }, + { + "name": "ipsec-user-mm-ipsec110-1791599034879", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791599034879-ca", + "invalid-before": "2026-10-10 05:24:00", + "invalid-after": "2026-10-12 05:24:00", + "common-name": "mm-ipsec110-1791599034879, QA+Team=VPN" + } + ], + [ + { + "name": "mm-ipsec110-1791599034879-client-imported", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:24:00", + "invalid-after": "2026-10-12 04:24:00", + "common-name": "mm-ipsec110-1791599034879, QA+Team=VPN" + }, + { + "name": "mm-ipsec110-1791599034879-ca-imported", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:23:56", + "invalid-after": "2026-10-12 04:23:56", + "common-name": "mm-ipsec110-1791599034879-CA" + } + ] + ], + "catalogCorrect": false + }, + "fullSubject": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791599279541", + "cn": "mm-ipsec110-1791599279541, QA+Team=\"VPN\"\\Lab", + "observations": [ + { + "serverId": 1, + "active": [ + { + ".id": "*1", + "id": "C=US, S=New York, L=Albany, O=Example, Ltd, OU=QA+Operations, CN=mm-ipsec110-1791599279541, QA+Team=\"VPN\"\\Lab", + "state": "established", + "dynamic-address": "198.18.110.250", + "remote-address": "104.165.244.7", + "uptime": "1s" + } + ], + "catalog": [ + { + "name": "mm-ipsec110-1791599279541", + "commonName": "mm-ipsec110-1791599279541, QA+Team=\"VPN\"\\Lab", + "certName": "ipsec-user-mm-ipsec110-1791599279541", + "online": false + } + ] + }, + { + "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-ipsec110-1791599279541", + "common-name": "mm-ipsec110-1791599279541, QA+Team=\"VPN\"\\Lab", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "state": "New York", + "locality": "Albany", + "ca": "mm-ipsec110-1791599279541-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "debug": [ + [ + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => certificate (size 0x381)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => peer's auth (size 0x100)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "peer authorized: mm-ipsec110-1791599034879 104.165.244.7-194.226.121.150 8b32523df8e1e6da:cefc293a7eb1e7fa" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 05:24:03", + "message": "mm-ipsec110-1791599034879: => my auth (size 0x100)" + }, + { + "time": "2026-10-10 05:28:07", + "message": "mm-ipsec110-1791599279541: => certificate (size 0x3ac)" + }, + { + "time": "2026-10-10 05:28:07", + "message": "mm-ipsec110-1791599279541: => peer's auth (size 0x100)" + }, + { + "time": "2026-10-10 05:28:07", + "message": "mm-ipsec110-1791599279541: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 05:28:07", + "message": "peer authorized: mm-ipsec110-1791599279541 104.165.244.7-194.226.121.150 c955a36f68061a2b:de97c72421f9d773" + }, + { + "time": "2026-10-10 05:28:07", + "message": "mm-ipsec110-1791599279541: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 05:28:07", + "message": "mm-ipsec110-1791599279541: => my auth (size 0x100)" + } + ], + [ + { + "time": "2026-10-10 04:24:03", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:24:03", + "message": "mm-ipsec110-1791599034879: => my auth (size 0x100)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "mm-ipsec110-1791599034879: => certificate (size 0x33f)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "mm-ipsec110-1791599034879: => peer's auth (size 0x100)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "mm-ipsec110-1791599034879: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:24:04", + "message": "peer authorized: mm-ipsec110-1791599034879 104.165.244.7-194.226.121.150 8b32523df8e1e6da:cefc293a7eb1e7fa" + }, + { + "time": "2026-10-10 04:28:07", + "message": "mm-ipsec110-1791599279541: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:28:07", + "message": "mm-ipsec110-1791599279541: => my auth (size 0x100)" + }, + { + "time": "2026-10-10 04:28:07", + "message": "mm-ipsec110-1791599279541: => certificate (size 0x33f)" + }, + { + "time": "2026-10-10 04:28:07", + "message": "mm-ipsec110-1791599279541: => peer's auth (size 0x100)" + }, + { + "time": "2026-10-10 04:28:07", + "message": "mm-ipsec110-1791599279541: => auth nonce (size 0x18)" + }, + { + "time": "2026-10-10 04:28:07", + "message": "peer authorized: mm-ipsec110-1791599279541 104.165.244.7-194.226.121.150 c955a36f68061a2b:de97c72421f9d773" + } + ] + ], + "certificates": [ + [ + { + "name": "mm-ipsec110-1791599279541-ca", + "trusted": "true", + "trust-store": "all", + "invalid-before": "2026-10-10 05:28:01", + "invalid-after": "2026-10-12 05:28:01", + "common-name": "mm-ipsec110-1791599279541-CA" + }, + { + "name": "mm-ipsec110-1791599279541-server", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791599279541-ca", + "invalid-before": "2026-10-10 05:28:02", + "invalid-after": "2026-10-12 05:28:02", + "common-name": "194.226.121.150" + }, + { + "name": "ipsec-user-mm-ipsec110-1791599279541", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791599279541-ca", + "invalid-before": "2026-10-10 05:28:03", + "invalid-after": "2026-10-12 05:28:03", + "common-name": "mm-ipsec110-1791599279541, QA+Team=\"VPN\"\\Lab" + } + ], + [ + { + "name": "mm-ipsec110-1791599279541-client-imported", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:28:03", + "invalid-after": "2026-10-12 04:28:03", + "common-name": "mm-ipsec110-1791599279541, QA+Team=\"VPN\"\\Lab" + }, + { + "name": "mm-ipsec110-1791599279541-ca-imported", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:28:01", + "invalid-after": "2026-10-12 04:28:01", + "common-name": "mm-ipsec110-1791599279541-CA" + } + ] + ], + "catalogCorrect": false + } + }, + "accepted": { + "date": "2026-10-10", + "block": "12.5.110", + "name": "mm-ipsec110-1791599881177", + "cn": "mm-ipsec110-1791599881177, QA+Team=\"VPN\"\\Lab", + "observations": [ + { + "serverId": 1, + "active": [ + { + ".id": "*1", + "id": "C=US, S=New York, L=Albany, O=Example, Ltd, OU=QA+Operations, CN=mm-ipsec110-1791599881177, QA+Team=\"VPN\"\\Lab", + "state": "established", + "dynamic-address": "198.18.110.250", + "remote-address": "104.165.244.7", + "uptime": "1s" + } + ], + "catalog": [ + { + "name": "mm-ipsec110-1791599881177", + "commonName": "mm-ipsec110-1791599881177, QA+Team=\"VPN\"\\Lab", + "certName": "ipsec-user-mm-ipsec110-1791599881177", + "online": true, + "activeAddress": "198.18.110.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-ipsec110-1791599881177", + "common-name": "mm-ipsec110-1791599881177, QA+Team=\"VPN\"\\Lab", + "organization": "Example, Ltd", + "unit": "QA+Operations", + "country": "US", + "state": "New York", + "locality": "Albany", + "ca": "mm-ipsec110-1791599881177-ca", + "key-usage": "digital-signature,key-encipherment,tls-client" + }, + "certificates": [ + [ + { + "name": "mm-ipsec110-1791599881177-ca", + "trusted": "true", + "trust-store": "all", + "invalid-before": "2026-10-10 05:38:02", + "invalid-after": "2026-10-12 05:38:02", + "common-name": "mm-ipsec110-1791599881177-CA" + }, + { + "name": "mm-ipsec110-1791599881177-server", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791599881177-ca", + "invalid-before": "2026-10-10 05:38:03", + "invalid-after": "2026-10-12 05:38:03", + "common-name": "194.226.121.150" + }, + { + "name": "ipsec-user-mm-ipsec110-1791599881177", + "trusted": "false", + "trust-store": "all", + "ca": "mm-ipsec110-1791599881177-ca", + "invalid-before": "2026-10-10 05:38:04", + "invalid-after": "2026-10-12 05:38:04", + "common-name": "mm-ipsec110-1791599881177, QA+Team=\"VPN\"\\Lab" + } + ], + [ + { + "name": "mm-ipsec110-1791599881177-client-imported", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:38:04", + "invalid-after": "2026-10-12 04:38:04", + "common-name": "mm-ipsec110-1791599881177, QA+Team=\"VPN\"\\Lab" + }, + { + "name": "mm-ipsec110-1791599881177-ca-imported", + "trusted": "true", + "trust-store": "ipsec", + "invalid-before": "2026-10-10 04:38:02", + "invalid-after": "2026-10-12 04:38:02", + "common-name": "mm-ipsec110-1791599881177-CA" + } + ] + ], + "catalogCorrect": true + }, + "preliminaryBrowser": { + "incorrectStorageKey": { + "report": { + "date": "2026-10-10", + "runtime": { + "backend": "ux-dn110", + "frontend": "ux-a11y101" + }, + "httpMocks": false, + "cases": [ + { + "theme": "dark", + "width": 1280, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + }, + { + "theme": "dark", + "width": 320, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + }, + { + "theme": "light", + "width": 1280, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + }, + { + "theme": "light", + "width": 320, + "onlineAddressConfirmed": true, + "reloadConfirmed": true, + "noPageOverflow": true + } + ], + "pageErrors": [], + "applicationWrites": [], + "scope": "Real established certificate DN client status/address, reload, desktop/mobile, two themes" + }, + "acceptedThemes": false, + "reason": "Helper used theme instead of rl-theme; these cases do not prove light theme" + }, + "detachedLocator": { + "date": "2026-10-10", + "error": "locator.scrollIntoViewIfNeeded: Element is not attached to the DOM", + "nativeAcceptance": true, + "cleanupPassed": true, + "resolution": "Reacquire the read-only locator on refresh, bounded 10s; no mutation retry" + } + }, + "browserEvidence": "browser-ipsec-dn-2026-10-10.json", + "deployment": { + "imageId": "sha256:f0cd7afc7391ac463c8b3c7d183b0c294f01ffca6beda3d240d26bec59c06d72", + "tag": "ux-dn110", + "revisionLabel": "dn110", + "health": { + "status": "ok", + "timestamp": "2026-10-10T02:34:19.932Z", + "version": "1.0.0-test.dn110", + "eventLoopDelayMs": 20, + "flowWorker": { + "alive": false, + "bound": false, + "pendingSize": 0, + "dropped": 0, + "packetsReceived": 0 + } + } + }, + "limits": [ + "RouterOS7.24.5 subject presentation confirmed; not a general ASN.1/RFC4514 parser", + "Native certificate matching/assigned address/UI status accepted; data-plane encryption was accepted in77–82, not re-tested here", + "Custom OIDs, alternate IKE ID namespaces, client OS, full PKI/restore/IPv6 remain open" + ] +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/ipsec-dn-source-2026-10-10.json b/docs/ux-ui/acceptance/ipsec-dn-source-2026-10-10.json new file mode 100644 index 00000000..7e8a41e7 --- /dev/null +++ b/docs/ux-ui/acceptance/ipsec-dn-source-2026-10-10.json @@ -0,0 +1,53 @@ +{ + "date": "2026-10-10", + "baseCommit": "1d61b50", + "baseContext": "build-patch102", + "context": "build-dn110", + "runtimeTag": "ux-dn110", + "source": "Base audited patch102 context plus explicit working-file overrides; label dn110 is not a Git SHA", + "files": [ + { + "path": "backend/src/services/ipsec-live.ts", + "sha256": "201fa6a0af955bd3217c002686e41b68a1737db1ee7195483b9bc6692c7aa655" + }, + { + "path": "backend/src/services/ipsec-certificate-dn.ts", + "sha256": "82a3bf8746dd928bfa9c0ec2a5ed6401d792cbe1390e14017d776e2fc8253d64" + }, + { + "path": "backend/src/services/ipsec-state.test.ts", + "sha256": "ca16dde47000ba310492c329ed8ee147ab1b150663c204071c68e99d8be94366" + } + ], + "deployment": { + "imageId": "sha256:f0cd7afc7391ac463c8b3c7d183b0c294f01ffca6beda3d240d26bec59c06d72", + "tag": "ux-dn110", + "revisionLabel": "dn110", + "health": { + "status": "ok", + "timestamp": "2026-10-10T02:34:19.932Z", + "version": "1.0.0-test.dn110", + "eventLoopDelayMs": 20, + "flowWorker": { + "alive": false, + "bound": false, + "pendingSize": 0, + "dropped": 0, + "packetsReceived": 0 + } + } + }, + "contextFileHashesMatch": true, + "compiledFiles": [ + { + "path": "backend/dist/services/ipsec-live.js", + "sha256": "6e2f94adfa2086617b3f08004e2c35321d6012113acdca1744ebd14553d34a9b", + "containerByteHashMatches": true + }, + { + "path": "backend/dist/services/ipsec-certificate-dn.js", + "sha256": "1da9af90d5deb3336dfa98b9bc49e85a21f0739d120bf52f9ed227b9e8616dc3", + "containerByteHashMatches": true + } + ] +} \ No newline at end of file diff --git a/docs/ux-ui/screens/ipsec-dn-dark-1280-2026-10-10.png b/docs/ux-ui/screens/ipsec-dn-dark-1280-2026-10-10.png new file mode 100644 index 00000000..7a7d0651 Binary files /dev/null and b/docs/ux-ui/screens/ipsec-dn-dark-1280-2026-10-10.png differ diff --git a/docs/ux-ui/screens/ipsec-dn-dark-320-2026-10-10.png b/docs/ux-ui/screens/ipsec-dn-dark-320-2026-10-10.png new file mode 100644 index 00000000..0e2a8768 Binary files /dev/null and b/docs/ux-ui/screens/ipsec-dn-dark-320-2026-10-10.png differ diff --git a/docs/ux-ui/screens/ipsec-dn-light-1280-2026-10-10.png b/docs/ux-ui/screens/ipsec-dn-light-1280-2026-10-10.png new file mode 100644 index 00000000..35ccb1de Binary files /dev/null and b/docs/ux-ui/screens/ipsec-dn-light-1280-2026-10-10.png differ diff --git a/docs/ux-ui/screens/ipsec-dn-light-320-2026-10-10.png b/docs/ux-ui/screens/ipsec-dn-light-320-2026-10-10.png new file mode 100644 index 00000000..dcd27c8d Binary files /dev/null and b/docs/ux-ui/screens/ipsec-dn-light-320-2026-10-10.png differ