fix(wireguard): удалять связанные пиры и IP вместе с интерфейсом
This commit is contained in:
1 parent
fe0ca3fa46
commit
3722fad329
11 files changed
+420
-8
No files matched your search
@@ -994,7 +994,7 @@ function WireGuardPageContent({ selectedServerId, selectedInterfaceId, allInterf
|
|||||||
</AlertDialogTitle>
|
</AlertDialogTitle>
|
||||||
<AlertDialogDescription className="break-all">
|
<AlertDialogDescription className="break-all">
|
||||||
{pendingDelete?.kind === "iface"
|
{pendingDelete?.kind === "iface"
|
||||||
? `${pendingDelete.iface.name} на ${pendingDelete.iface.serverName}. Вместе с интерфейсом будут удалены связанные пиры на роутере.`
|
? `${pendingDelete.iface.name} на ${pendingDelete.iface.serverName}. Вместе с интерфейсом будут удалены связанные пиры и IP-адреса на роутере.`
|
||||||
: pendingDelete
|
: pendingDelete
|
||||||
? `Пир «${pendingPeer?.name || pendingPeer?.publicKey || pendingDelete.peerId}» (ID ${pendingDelete.peerId}) на ${pendingDelete.iface.name} (${pendingDelete.iface.serverName}).`
|
? `Пир «${pendingPeer?.name || pendingPeer?.publicKey || pendingDelete.peerId}» (ID ${pendingDelete.peerId}) на ${pendingDelete.iface.name} (${pendingDelete.iface.serverName}).`
|
||||||
: null}
|
: null}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
type WgIfaceDto,
|
type WgIfaceDto,
|
||||||
} from "@mmapp/contracts/wireguard"
|
} from "@mmapp/contracts/wireguard"
|
||||||
import { MikrotikClient, MikrotikError } from "../services/mikrotik.js"
|
import { MikrotikClient, MikrotikError } from "../services/mikrotik.js"
|
||||||
|
import { deleteWireguardInterface } from "../services/wireguard-delete.js"
|
||||||
import {
|
import {
|
||||||
generateMikrotikRsc,
|
generateMikrotikRsc,
|
||||||
generateNativeConf,
|
generateNativeConf,
|
||||||
@@ -256,7 +257,7 @@ const wireguardRoutes: FastifyPluginAsyncZod = async (app) => {
|
|||||||
if (!server) return reply.status(404).send({ error: "Сервер не найден" })
|
if (!server) return reply.status(404).send({ error: "Сервер не найден" })
|
||||||
const client = MikrotikClient.fromServer(server)
|
const client = MikrotikClient.fromServer(server)
|
||||||
try {
|
try {
|
||||||
await client.delete(`/interface/wireguard/${encodeURIComponent(rosIdParam(rosId))}`)
|
await deleteWireguardInterface(client, rosIdParam(rosId))
|
||||||
await recordWireguard(server, "apply")
|
await recordWireguard(server, "apply")
|
||||||
return reply.send({ ok: true })
|
return reply.send({ ok: true })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { test } from 'node:test'
|
||||||
|
import { deleteWireguardInterface } from './wireguard-delete.js'
|
||||||
|
|
||||||
|
type Row = { '.id': string; name?: string; interface?: string }
|
||||||
|
function fixture(opts: { failRead?: string; failDelete?: string; keep?: string; missing?: boolean } = {}) {
|
||||||
|
const rows: Record<string, Row[]> = {
|
||||||
|
'/interface/wireguard': [{ '.id': '*A/1', name: 'wg-own' }, { '.id': '*B', name: 'wg-foreign' }],
|
||||||
|
'/interface/wireguard/peers': [{ '.id': '*P', interface: 'wg-own' }, { '.id': '*Q', interface: '*A/1' }, { '.id': '*F', interface: 'wg-foreign' }],
|
||||||
|
'/ip/address': [{ '.id': '*I', interface: 'wg-own' }, { '.id': '*J', interface: 'wg-foreign' }],
|
||||||
|
}
|
||||||
|
if (opts.missing) rows['/interface/wireguard'] = rows['/interface/wireguard'].filter(r => r.name !== 'wg-own')
|
||||||
|
const deletes: string[] = []
|
||||||
|
const client = {
|
||||||
|
async get<T>(path: string): Promise<T> {
|
||||||
|
if (path === opts.failRead) throw new Error('Read forbidden')
|
||||||
|
return structuredClone(rows[path]) as T
|
||||||
|
},
|
||||||
|
async delete(path: string): Promise<void> {
|
||||||
|
deletes.push(path)
|
||||||
|
if (path === opts.failDelete) throw new Error('Delete forbidden')
|
||||||
|
const split = path.lastIndexOf('/'), base = path.slice(0, split), id = decodeURIComponent(path.slice(split + 1))
|
||||||
|
if (base !== opts.keep) rows[base] = rows[base].filter(row => row['.id'] !== id)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return { client, rows, deletes }
|
||||||
|
}
|
||||||
|
|
||||||
|
test('removes named/id-associated peers and addresses before interface; preserves foreign objects', async () => {
|
||||||
|
const f = fixture(); await deleteWireguardInterface(f.client, '*A/1')
|
||||||
|
assert.deepEqual(f.deletes, ['/interface/wireguard/peers/*P', '/interface/wireguard/peers/*Q', '/ip/address/*I', '/interface/wireguard/*A%2F1'])
|
||||||
|
assert.deepEqual(f.rows['/interface/wireguard'], [{ '.id': '*B', name: 'wg-foreign' }])
|
||||||
|
assert.deepEqual(f.rows['/interface/wireguard/peers'], [{ '.id': '*F', interface: 'wg-foreign' }])
|
||||||
|
assert.deepEqual(f.rows['/ip/address'], [{ '.id': '*J', interface: 'wg-foreign' }])
|
||||||
|
})
|
||||||
|
for (const path of ['/interface/wireguard', '/interface/wireguard/peers', '/ip/address']) {
|
||||||
|
test(`read failure ${path} prevents every write`, async () => {
|
||||||
|
const f = fixture({ failRead: path }); await assert.rejects(deleteWireguardInterface(f.client, '*A/1'), /Read forbidden/); assert.deepEqual(f.deletes, [])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
test('unknown interface never touches foreign resources', async () => {
|
||||||
|
const f = fixture({ missing: true }); await assert.rejects(deleteWireguardInterface(f.client, '*A/1'), /не найден/); assert.deepEqual(f.deletes, [])
|
||||||
|
})
|
||||||
|
test('partial failure is surfaced and interface remains available for retry', async () => {
|
||||||
|
const f = fixture({ failDelete: '/ip/address/*I' }); await assert.rejects(deleteWireguardInterface(f.client, '*A/1'), /Delete forbidden/)
|
||||||
|
assert(f.rows['/interface/wireguard'].some(r => r.name === 'wg-own'))
|
||||||
|
await deleteWireguardInterface({ ...f.client, async delete(path) { const split = path.lastIndexOf('/'), base = path.slice(0, split), id = decodeURIComponent(path.slice(split + 1)); f.rows[base] = f.rows[base].filter(r => r['.id'] !== id) } }, '*A/1')
|
||||||
|
assert.deepEqual(f.rows['/ip/address'], [{ '.id': '*J', interface: 'wg-foreign' }])
|
||||||
|
})
|
||||||
|
for (const path of ['/interface/wireguard', '/interface/wireguard/peers', '/ip/address']) {
|
||||||
|
test(`unconfirmed removal ${path} cannot report success`, async () => {
|
||||||
|
const f = fixture({ keep: path }); await assert.rejects(deleteWireguardInterface(f.client, '*A/1'), /не подтвердил/)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import type { MikrotikClient } from "./mikrotik.js"
|
||||||
|
|
||||||
|
type RosRow = { ".id"?: string; name?: string; interface?: string }
|
||||||
|
type Client = Pick<MikrotikClient, "get" | "delete">
|
||||||
|
|
||||||
|
/** RouterOS retains peer/address records when their WireGuard interface is removed. */
|
||||||
|
export async function deleteWireguardInterface(client: Client, rosId: string): Promise<void> {
|
||||||
|
const interfaces = await client.get<RosRow[]>("/interface/wireguard")
|
||||||
|
const target = interfaces.find(row => row[".id"] === rosId)
|
||||||
|
if (!target?.name) throw new Error("Интерфейс WireGuard не найден; удаление не выполнено")
|
||||||
|
const name = target.name
|
||||||
|
const belongs = (row: RosRow) => row.interface === name || row.interface === rosId
|
||||||
|
const [peers, addresses] = await Promise.all([
|
||||||
|
client.get<RosRow[]>("/interface/wireguard/peers"),
|
||||||
|
client.get<RosRow[]>("/ip/address"),
|
||||||
|
])
|
||||||
|
const groups = [
|
||||||
|
{ path: "/interface/wireguard/peers", rows: peers.filter(belongs) },
|
||||||
|
{ path: "/ip/address", rows: addresses.filter(belongs) },
|
||||||
|
]
|
||||||
|
// Finish all reads and validate identities before the first destructive request.
|
||||||
|
if (groups.some(group => group.rows.some(row => !row[".id"]))) {
|
||||||
|
throw new Error("Не удалось определить связанные объекты WireGuard; удаление не выполнено")
|
||||||
|
}
|
||||||
|
for (const group of groups) {
|
||||||
|
for (const row of group.rows) await client.delete(`${group.path}/${encodeURIComponent(row[".id"]!)}`)
|
||||||
|
}
|
||||||
|
await client.delete(`/interface/wireguard/${encodeURIComponent(rosId)}`)
|
||||||
|
const [remainingInterfaces, remainingPeers, remainingAddresses] = await Promise.all([
|
||||||
|
client.get<RosRow[]>("/interface/wireguard"),
|
||||||
|
client.get<RosRow[]>("/interface/wireguard/peers"),
|
||||||
|
client.get<RosRow[]>("/ip/address"),
|
||||||
|
])
|
||||||
|
const hasRemaining = (rows: RosRow[], original: RosRow[]) => rows.some(row => belongs(row) || original.some(before => before[".id"] === row[".id"]))
|
||||||
|
if (remainingInterfaces.some(row => row[".id"] === rosId || row.name === name)
|
||||||
|
|| hasRemaining(remainingPeers, groups[0].rows)
|
||||||
|
|| hasRemaining(remainingAddresses, groups[1].rows)) {
|
||||||
|
throw new Error("RouterOS не подтвердил полное удаление интерфейса WireGuard и связанных объектов")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: протокол внешней приёмки 12.5
|
# UX/UI: протокол внешней приёмки 12.5
|
||||||
|
|
||||||
Статус на2026-10-08: backendbd3f996/frontendfd521f6, backend healthy. Мобильная GRE форма и native сохранение на обоих CHR приняты в12.5.57. WireGuard handshake/короткий Ping/native API/read-only UI приняты в границах12.5.58; обычное удаление интерфейса с IP ещё не проверено. Устойчивость меню GRE при live refresh на обоих CHR принята в12.5.55. GRE peer metadata и реальный lifecycle/API/UI/двусторонний Ping подтверждены в12.5.53. Browser retry/checkpoint на реальном HTTP/PG принят в границах12.5.43–45; Telegram sender responses подменены, реальная доставка не проверена. PG-1/2/3/4/5 приняты в описанных границах, PG-6 integrated для одного isolated instance, PG-7 real JWT/processcounts и browser restore passed. PG-8 real PG/native и browser unknown→history done приняты с fault injection после настоящего COMMIT. ROS-8/9 real API/SQL/native приняты в границах12.5.23; browser pair/duration change и delete приняты в12.5.24. ROS-2 authentication failure принят в12.5.25. PortalSSO, физический TCP disconnect, мультиэкземпляры и остальные ROS/Q/интеграции остаются открытыми. [Паспорт](ux-ui-test-server.md), [журнал](ux-ui-progress.md).
|
Статус на2026-10-08: backendbd3f996/frontendfd521f6, backend healthy. Мобильная GRE форма и native сохранение на обоих CHR приняты в12.5.57. WireGuard handshake/короткий Ping/native API/read-only UI приняты в границах12.5.58; 12.5.59 воспроизвёл оставшиеся peers/IP после обычного удаления; локальное исправление ещё не развёрнуто, приёмка удаления открыта. Устойчивость меню GRE при live refresh на обоих CHR принята в12.5.55. GRE peer metadata и реальный lifecycle/API/UI/двусторонний Ping подтверждены в12.5.53. Browser retry/checkpoint на реальном HTTP/PG принят в границах12.5.43–45; Telegram sender responses подменены, реальная доставка не проверена. PG-1/2/3/4/5 приняты в описанных границах, PG-6 integrated для одного isolated instance, PG-7 real JWT/processcounts и browser restore passed. PG-8 real PG/native и browser unknown→history done приняты с fault injection после настоящего COMMIT. ROS-8/9 real API/SQL/native приняты в границах12.5.23; browser pair/duration change и delete приняты в12.5.24. ROS-2 authentication failure принят в12.5.25. PortalSSO, физический TCP disconnect, мультиэкземпляры и остальные ROS/Q/интеграции остаются открытыми. [Паспорт](ux-ui-test-server.md), [журнал](ux-ui-progress.md).
|
||||||
|
|
||||||
## Паспорт стенда
|
## Паспорт стенда
|
||||||
|
|
||||||
@@ -429,3 +429,15 @@ DELETE200/200, собственные GRE/IP/connected routes удалены; в
|
|||||||
[Первый проход](ux-ui/acceptance/wg-real-first-attempt-2026-10-08.json) подтвердил связность/UI, но cleanup harness получил DELETE400: Content-Type application/json был передан без тела. Это ошибка harness, не доказательство ошибки приложения. [Восстановительная очистка](ux-ui/acceptance/wg-first-cleanup-recovery-2026-10-08.json) через правильные DELETE проверила ownership comment/name и отсутствие own interfaces/peers/IP/routes. Baseline первого прохода был только в памяти и после выхода потерян; точная сверка первого baseline не заявляется. Harness исправлен, создана новая пара и повторён полный lifecycle/browser; итоговый exit0 и все выбранные baseline поля совпали.
|
[Первый проход](ux-ui/acceptance/wg-real-first-attempt-2026-10-08.json) подтвердил связность/UI, но cleanup harness получил DELETE400: Content-Type application/json был передан без тела. Это ошибка harness, не доказательство ошибки приложения. [Восстановительная очистка](ux-ui/acceptance/wg-first-cleanup-recovery-2026-10-08.json) через правильные DELETE проверила ownership comment/name и отсутствие own interfaces/peers/IP/routes. Baseline первого прохода был только в памяти и после выхода потерян; точная сверка первого baseline не заявляется. Harness исправлен, создана новая пара и повторён полный lifecycle/browser; итоговый exit0 и все выбранные baseline поля совпали.
|
||||||
|
|
||||||
В финальном cleanup собственные peers удалены API200/200, собственные IP явно удалены native API до удаления interfaces API200/200. Автоматическая очистка IP/peers при обычном удалении интерфейса НЕ проверена и остаётся следующим12.5.59. WireGuard/IP/routes/IPv4 Firewall выбранные настройки совпали с baseline; эфемерный контейнер удалён, работают только три основные Compose-службы. DB controls до/после servers2/speedHistory9/retention14/migrations9 совпали, backend healthy. WG revisions намеренно сохранены как история операций. Runtime backendbd3f996/frontendfd521f6 не менялся. Telegram/Portal/multi-instance и остальные внешние ограничения остаются открытыми. Локальный коммит без push.
|
В финальном cleanup собственные peers удалены API200/200, собственные IP явно удалены native API до удаления interfaces API200/200. Автоматическая очистка IP/peers при обычном удалении интерфейса НЕ проверена и остаётся следующим12.5.59. WireGuard/IP/routes/IPv4 Firewall выбранные настройки совпали с baseline; эфемерный контейнер удалён, работают только три основные Compose-службы. DB controls до/после servers2/speedHistory9/retention14/migrations9 совпали, backend healthy. WG revisions намеренно сохранены как история операций. Runtime backendbd3f996/frontendfd521f6 не менялся. Telegram/Portal/multi-instance и остальные внешние ограничения остаются открытыми. Локальный коммит без push.
|
||||||
|
|
||||||
|
## 12.5.59 — удаление WireGuard оставляло peer и IP; локальное исправление (2026-10-08)
|
||||||
|
|
||||||
|
[Production UI](ux-ui/acceptance/browser-wg-delete-2026-10-08.json): собственная новая пара mm-acceptance-wg-1791471219775, подтверждённые handshake/двусторонний Ping. Интерфейсы удалены через стандартные меню и AlertDialog приложения на обоих CHR (ПК/320px). DELETE200/200 закрыли диалоги, но независимое native чтение обнаружило на каждом устройстве оставшийся peer и собственный IPv4 адрес. Это подтверждённая ошибка backendbd3f996: route удалял только /interface/wireguard/id, RouterOS сохранил связанные записи.
|
||||||
|
|
||||||
|
[Native проверка и восстановительная очистка](ux-ui/acceptance/wg-real-delete-2026-10-08.json): afterBrowserDelete содержит interface:null, peerCount1 и собственный адрес на каждом CHR. Harness сохранил исходные идентификаторы own peers/IP и удалил только эти остатки, даже после исчезновения интерфейса. Финальный exit0, выбранные WG/peers/IP/routes/IPv4 Firewall поля совпали с baseline; ephemeral контейнер удалён, остались три основные службы. Это очистка теста, а не успешная приёмка стандартного удаления. Ключи не включены в публичные отчёты; WG revisions намеренно сохранены.
|
||||||
|
|
||||||
|
Локально добавлен backend/src/services/wireguard-delete.ts и подключён к DELETE route: идентификация интерфейса по rosId, чтение peers и IPv4 адресов до первой записи, отбор только связанных с именем/rosId объектов, удаление peers→addresses→interface, независимое перечитывание и ошибка при оставшихся объектах. При read failure запись не начинается; при промежуточной ошибке дальнейшее удаление прекращается, ошибка возвращается вместо ok. Успех и apply revision происходят только после проверки отсутствия объектов. Это последовательные RouterOS операции, не транзакция: частичный сбой может оставить частично удалённые данные, потребуется повтор/обновление. Текст подтверждения в WireGuard page теперь указывает связанные пиры и IP-адреса.
|
||||||
|
|
||||||
|
Проверки backend/src/services/wireguard-delete.test.ts —9/9: чужие объекты сохранены, связи по имени/rosId, encoded ID, ошибки всех предварительных чтений, неизвестный интерфейс, частичная ошибка/повтор, неподтверждённое удаление каждой группы. Profile UI tests wireguard-links.spec.ts --grep deletion/удал —2/2: подтверждение удаления интерфейса/пира, запрет повторного нажатия и повтор после API ошибки. Backend TypeScript, scoped frontend TypeScript (tmp/tsconfig-speed-check.json), ESLint изменённых файлов и ReUI checklist passed. Примитивы/таблицы не менялись.
|
||||||
|
|
||||||
|
Исправление пока локальное: удалённый backendbd3f996/frontendfd521f6 остаётся прежним. Следующий12.5.60 — production Docker build/deploy обеих частей, новая собственная WireGuard пара и обычное UI/API удаление без предварительного удаления peer/IP, независимая проверка отсутствия остатков и baseline, очистка fallback только own объектов. IPv6 address lifecycle, concurrency/multi-instance, Telegram/Portal и другие внешние ограничения не проверены. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
|
||||||
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
# План реализации UX/UI по пятичасовым окнам
|
# План реализации UX/UI по пятичасовым окнам
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-08: 12.5.58 подтвердил настоящую WireGuard пару на обоих CHR: API/native keys association, handshake/RX, Ping3/3, MTU и UI в двух темах/1280/320px, URL interface/server/tab/reload. Итоговый harness exit0, выбранный WG/peers/IP/routes/Firewall baseline и DB controls совпали; own объекты удалены. Первый DELETE harness400 из-за JSON header без тела исправлен, recovery и повторный полный проход сохранены отдельно. Runtime backendbd3f996/frontendfd521f6 healthy. Следующий12.5.59 — удалить собственный WireGuard интерфейс с peer/IP через обычный UI/API и проверить остаточные объекты; в58 IP удалялись явно. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-08: 12.5.59 воспроизвёл ошибку удаления WireGuard через production UI на обоих CHR: DELETE200 удалял только интерфейс, оставляя peer и IP. Own остатки очищены, выбранный baseline совпал. Локально добавлено связанное удаление peers/IPv4 addresses/interface с проверкой результата; unit9/9, UI deletion2/2, backend/frontend TypeScript и ESLint passed. Runtime backendbd3f996/frontendfd521f6 healthy ещё содержит прежнее поведение. Следующий12.5.60 — Docker build/deploy backend и frontend, повторить обычное удаление собственной WG пары без предварительной очистки peer/IP и сверить baseline. Этап12.5 открыт.
|
||||||
|
|
||||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-08. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-08. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||||
|
|
||||||
## Актуальная точка продолжения — 2026-10-08
|
## Актуальная точка продолжения — 2026-10-08
|
||||||
|
|
||||||
Этапы0–11 завершены в описанных локальных границах. Этап12 открыт. На тестовом сервере161.104.46.222 работают backendbd3f996/frontendfd521f6 и два CHR. Внешние проверки подтвердили PG backup/restore/rollback, остановку фоновой работы для одного экземпляра, API JWT/RBAC и браузерные состояния восстановления. Native TCP/UDP speed, история и UI проверены в границах журнала; доступ ко второму CHR восстановлен пользователем. Очередь Telegram проверена на реальном PG: dedupe, конкурентный claim, retry/version, ошибки сохранения и неопределённый исход; ответы отправителя подменялись, реальной доставки это не доказывает. Блоки12.5.43–45 подтвердили browser retry/checkpoint и развернули понятное пояснение HTTP500. 12.5.46 подтвердил browser JWT/RBAC очереди на реальном HTTP/PG; 12.5.47 подтвердил изоляцию checkpoint при смене двух реальных HTTP/PG источников в конфигурации local; 12.5.48 подтвердил scoped axe/клавиатуру в обеих темах и320px; 12.5.49 собрал Q-матрицу и подтвердил отсутствие настройки Telegram; 12.5.50 подтвердил GET-only инвентаризацию: VPN/BGP/OSPF пусты, роли home-router/home-router; По уточнению пользователя12.5.51 создал реальные GRE туннели и подтвердил lifecycle/связность; обнаружена потеря peer IP, 12.5.52 локально исправил сохранение peer metadata, профильные проверки passed; 12.5.53 развернул исправление и подтвердил его на реальной GRE паре/API/UI; 12.5.54 локально исправил устойчивость меню GRE, профильные проверки passed; 12.5.55 развернул frontend731803b и подтвердил устойчивость меню на реальной GRE паре; 12.5.56 локально адаптировал внутренние IP поля GRE для320px, обе темы и профильные проверки passed; 12.5.57 развернул frontendfd521f6 и подтвердил мобильную GRE форму на реальной паре CHR; 12.5.58 подтвердил настоящую WireGuard пару, handshake/Ping/native/UI и финальную очистку; следующий12.5.59 — обычное удаление WireGuard интерфейса с peer/IP через UI/API, проверка оставшихся объектов. Реальная Telegram доставка, Portal SSO, физический TCP disconnect, multi-instance и остальные профильные сетевые сценарии остаются открытыми. [Протокол](ux-ui-external-acceptance.md) и [журнал](ux-ui-stage-12.md) содержат доказательства и ограничения.
|
Этапы0–11 завершены в описанных локальных границах. Этап12 открыт. На тестовом сервере161.104.46.222 работают backendbd3f996/frontendfd521f6 и два CHR. Внешние проверки подтвердили PG backup/restore/rollback, остановку фоновой работы для одного экземпляра, API JWT/RBAC и браузерные состояния восстановления. Native TCP/UDP speed, история и UI проверены в границах журнала; доступ ко второму CHR восстановлен пользователем. Очередь Telegram проверена на реальном PG: dedupe, конкурентный claim, retry/version, ошибки сохранения и неопределённый исход; ответы отправителя подменялись, реальной доставки это не доказывает. Блоки12.5.43–45 подтвердили browser retry/checkpoint и развернули понятное пояснение HTTP500. 12.5.46 подтвердил browser JWT/RBAC очереди на реальном HTTP/PG; 12.5.47 подтвердил изоляцию checkpoint при смене двух реальных HTTP/PG источников в конфигурации local; 12.5.48 подтвердил scoped axe/клавиатуру в обеих темах и320px; 12.5.49 собрал Q-матрицу и подтвердил отсутствие настройки Telegram; 12.5.50 подтвердил GET-only инвентаризацию: VPN/BGP/OSPF пусты, роли home-router/home-router; По уточнению пользователя12.5.51 создал реальные GRE туннели и подтвердил lifecycle/связность; обнаружена потеря peer IP, 12.5.52 локально исправил сохранение peer metadata, профильные проверки passed; 12.5.53 развернул исправление и подтвердил его на реальной GRE паре/API/UI; 12.5.54 локально исправил устойчивость меню GRE, профильные проверки passed; 12.5.55 развернул frontend731803b и подтвердил устойчивость меню на реальной GRE паре; 12.5.56 локально адаптировал внутренние IP поля GRE для320px, обе темы и профильные проверки passed; 12.5.57 развернул frontendfd521f6 и подтвердил мобильную GRE форму на реальной паре CHR; 12.5.58 подтвердил настоящую WireGuard пару, handshake/Ping/native/UI и финальную очистку; 12.5.59 подтвердил оставшиеся peers/IP после удаления WG и локально исправил backend; следующий12.5.60 — Docker deploy и повторная реальная приёмка обычного удаления. Реальная Telegram доставка, Portal SSO, физический TCP disconnect, multi-instance и остальные профильные сетевые сценарии остаются открытыми. [Протокол](ux-ui-external-acceptance.md) и [журнал](ux-ui-stage-12.md) содержат доказательства и ограничения.
|
||||||
|
|
||||||
Выполненные внешние сценарии не заменяют приёмку оставшихся интеграций и условий эксплуатации. Датированные продолжения ниже — история; точный следующий шаг указан в начале [журнала](ux-ui-progress.md).
|
Выполненные внешние сценарии не заменяют приёмку оставшихся интеграций и условий эксплуатации. Датированные продолжения ниже — история; точный следующий шаг указан в начале [журнала](ux-ui-progress.md).
|
||||||
|
|
||||||
|
|||||||
+14
-2
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: журнал реализации
|
# UX/UI: журнал реализации
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-08: 12.5.58 подтвердил настоящую WireGuard пару на обоих CHR: API/native keys association, handshake/RX, Ping3/3, MTU и UI в двух темах/1280/320px, URL interface/server/tab/reload. Итоговый harness exit0, выбранный WG/peers/IP/routes/Firewall baseline и DB controls совпали; own объекты удалены. Первый DELETE harness400 из-за JSON header без тела исправлен, recovery и повторный полный проход сохранены отдельно. Runtime backendbd3f996/frontendfd521f6 healthy. Следующий12.5.59 — удалить собственный WireGuard интерфейс с peer/IP через обычный UI/API и проверить остаточные объекты; в58 IP удалялись явно. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-08: 12.5.59 воспроизвёл ошибку удаления WireGuard через production UI на обоих CHR: DELETE200 удалял только интерфейс, оставляя peer и IP. Own остатки очищены, выбранный baseline совпал. Локально добавлено связанное удаление peers/IPv4 addresses/interface с проверкой результата; unit9/9, UI deletion2/2, backend/frontend TypeScript и ESLint passed. Runtime backendbd3f996/frontendfd521f6 healthy ещё содержит прежнее поведение. Следующий12.5.60 — Docker build/deploy backend и frontend, повторить обычное удаление собственной WG пары без предварительной очистки peer/IP и сверить baseline. Этап12.5 открыт.
|
||||||
|
|
||||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||||
|
|
||||||
@@ -34,7 +34,19 @@
|
|||||||
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
||||||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
||||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–58 и ограничения ниже. Runtime backendbd3f996/frontendfd521f6. |
|
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–59 и ограничения ниже. Runtime backendbd3f996/frontendfd521f6. |
|
||||||
|
|
||||||
|
## 12.5.59 — удаление WireGuard оставляло peer и IP; локальное исправление (2026-10-08)
|
||||||
|
|
||||||
|
[Production UI](ux-ui/acceptance/browser-wg-delete-2026-10-08.json): собственная новая пара mm-acceptance-wg-1791471219775, подтверждённые handshake/двусторонний Ping. Интерфейсы удалены через стандартные меню и AlertDialog приложения на обоих CHR (ПК/320px). DELETE200/200 закрыли диалоги, но независимое native чтение обнаружило на каждом устройстве оставшийся peer и собственный IPv4 адрес. Это подтверждённая ошибка backendbd3f996: route удалял только /interface/wireguard/id, RouterOS сохранил связанные записи.
|
||||||
|
|
||||||
|
[Native проверка и восстановительная очистка](ux-ui/acceptance/wg-real-delete-2026-10-08.json): afterBrowserDelete содержит interface:null, peerCount1 и собственный адрес на каждом CHR. Harness сохранил исходные идентификаторы own peers/IP и удалил только эти остатки, даже после исчезновения интерфейса. Финальный exit0, выбранные WG/peers/IP/routes/IPv4 Firewall поля совпали с baseline; ephemeral контейнер удалён, остались три основные службы. Это очистка теста, а не успешная приёмка стандартного удаления. Ключи не включены в публичные отчёты; WG revisions намеренно сохранены.
|
||||||
|
|
||||||
|
Локально добавлен backend/src/services/wireguard-delete.ts и подключён к DELETE route: идентификация интерфейса по rosId, чтение peers и IPv4 адресов до первой записи, отбор только связанных с именем/rosId объектов, удаление peers→addresses→interface, независимое перечитывание и ошибка при оставшихся объектах. При read failure запись не начинается; при промежуточной ошибке дальнейшее удаление прекращается, ошибка возвращается вместо ok. Успех и apply revision происходят только после проверки отсутствия объектов. Это последовательные RouterOS операции, не транзакция: частичный сбой может оставить частично удалённые данные, потребуется повтор/обновление. Текст подтверждения в WireGuard page теперь указывает связанные пиры и IP-адреса.
|
||||||
|
|
||||||
|
Проверки backend/src/services/wireguard-delete.test.ts —9/9: чужие объекты сохранены, связи по имени/rosId, encoded ID, ошибки всех предварительных чтений, неизвестный интерфейс, частичная ошибка/повтор, неподтверждённое удаление каждой группы. Profile UI tests wireguard-links.spec.ts --grep deletion/удал —2/2: подтверждение удаления интерфейса/пира, запрет повторного нажатия и повтор после API ошибки. Backend TypeScript, scoped frontend TypeScript (tmp/tsconfig-speed-check.json), ESLint изменённых файлов и ReUI checklist passed. Примитивы/таблицы не менялись.
|
||||||
|
|
||||||
|
Исправление пока локальное: удалённый backendbd3f996/frontendfd521f6 остаётся прежним. Следующий12.5.60 — production Docker build/deploy обеих частей, новая собственная WireGuard пара и обычное UI/API удаление без предварительного удаления peer/IP, независимая проверка отсутствия остатков и baseline, очистка fallback только own объектов. IPv6 address lifecycle, concurrency/multi-instance, Telegram/Portal и другие внешние ограничения не проверены. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
|
||||||
|
|
||||||
## 12.5.58 — настоящая WireGuard пара, handshake и UI (2026-10-08)
|
## 12.5.58 — настоящая WireGuard пара, handshake и UI (2026-10-08)
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -1,6 +1,6 @@
|
|||||||
# Этап 12: итоговая приёмка UX/UI
|
# Этап 12: итоговая приёмка UX/UI
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-08: 12.5.58 подтвердил настоящую WireGuard пару на обоих CHR: API/native keys association, handshake/RX, Ping3/3, MTU и UI в двух темах/1280/320px, URL interface/server/tab/reload. Итоговый harness exit0, выбранный WG/peers/IP/routes/Firewall baseline и DB controls совпали; own объекты удалены. Первый DELETE harness400 из-за JSON header без тела исправлен, recovery и повторный полный проход сохранены отдельно. Runtime backendbd3f996/frontendfd521f6 healthy. Следующий12.5.59 — удалить собственный WireGuard интерфейс с peer/IP через обычный UI/API и проверить остаточные объекты; в58 IP удалялись явно. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-08: 12.5.59 воспроизвёл ошибку удаления WireGuard через production UI на обоих CHR: DELETE200 удалял только интерфейс, оставляя peer и IP. Own остатки очищены, выбранный baseline совпал. Локально добавлено связанное удаление peers/IPv4 addresses/interface с проверкой результата; unit9/9, UI deletion2/2, backend/frontend TypeScript и ESLint passed. Runtime backendbd3f996/frontendfd521f6 healthy ещё содержит прежнее поведение. Следующий12.5.60 — Docker build/deploy backend и frontend, повторить обычное удаление собственной WG пары без предварительной очистки peer/IP и сверить baseline. Этап12.5 открыт.
|
||||||
|
|
||||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||||
|
|
||||||
@@ -1594,3 +1594,15 @@ DELETE200/200, собственные GRE/IP/connected routes удалены; в
|
|||||||
[Первый проход](ux-ui/acceptance/wg-real-first-attempt-2026-10-08.json) подтвердил связность/UI, но cleanup harness получил DELETE400: Content-Type application/json был передан без тела. Это ошибка harness, не доказательство ошибки приложения. [Восстановительная очистка](ux-ui/acceptance/wg-first-cleanup-recovery-2026-10-08.json) через правильные DELETE проверила ownership comment/name и отсутствие own interfaces/peers/IP/routes. Baseline первого прохода был только в памяти и после выхода потерян; точная сверка первого baseline не заявляется. Harness исправлен, создана новая пара и повторён полный lifecycle/browser; итоговый exit0 и все выбранные baseline поля совпали.
|
[Первый проход](ux-ui/acceptance/wg-real-first-attempt-2026-10-08.json) подтвердил связность/UI, но cleanup harness получил DELETE400: Content-Type application/json был передан без тела. Это ошибка harness, не доказательство ошибки приложения. [Восстановительная очистка](ux-ui/acceptance/wg-first-cleanup-recovery-2026-10-08.json) через правильные DELETE проверила ownership comment/name и отсутствие own interfaces/peers/IP/routes. Baseline первого прохода был только в памяти и после выхода потерян; точная сверка первого baseline не заявляется. Harness исправлен, создана новая пара и повторён полный lifecycle/browser; итоговый exit0 и все выбранные baseline поля совпали.
|
||||||
|
|
||||||
В финальном cleanup собственные peers удалены API200/200, собственные IP явно удалены native API до удаления interfaces API200/200. Автоматическая очистка IP/peers при обычном удалении интерфейса НЕ проверена и остаётся следующим12.5.59. WireGuard/IP/routes/IPv4 Firewall выбранные настройки совпали с baseline; эфемерный контейнер удалён, работают только три основные Compose-службы. DB controls до/после servers2/speedHistory9/retention14/migrations9 совпали, backend healthy. WG revisions намеренно сохранены как история операций. Runtime backendbd3f996/frontendfd521f6 не менялся. Telegram/Portal/multi-instance и остальные внешние ограничения остаются открытыми. Локальный коммит без push.
|
В финальном cleanup собственные peers удалены API200/200, собственные IP явно удалены native API до удаления interfaces API200/200. Автоматическая очистка IP/peers при обычном удалении интерфейса НЕ проверена и остаётся следующим12.5.59. WireGuard/IP/routes/IPv4 Firewall выбранные настройки совпали с baseline; эфемерный контейнер удалён, работают только три основные Compose-службы. DB controls до/после servers2/speedHistory9/retention14/migrations9 совпали, backend healthy. WG revisions намеренно сохранены как история операций. Runtime backendbd3f996/frontendfd521f6 не менялся. Telegram/Portal/multi-instance и остальные внешние ограничения остаются открытыми. Локальный коммит без push.
|
||||||
|
|
||||||
|
## 12.5.59 — удаление WireGuard оставляло peer и IP; локальное исправление (2026-10-08)
|
||||||
|
|
||||||
|
[Production UI](ux-ui/acceptance/browser-wg-delete-2026-10-08.json): собственная новая пара mm-acceptance-wg-1791471219775, подтверждённые handshake/двусторонний Ping. Интерфейсы удалены через стандартные меню и AlertDialog приложения на обоих CHR (ПК/320px). DELETE200/200 закрыли диалоги, но независимое native чтение обнаружило на каждом устройстве оставшийся peer и собственный IPv4 адрес. Это подтверждённая ошибка backendbd3f996: route удалял только /interface/wireguard/id, RouterOS сохранил связанные записи.
|
||||||
|
|
||||||
|
[Native проверка и восстановительная очистка](ux-ui/acceptance/wg-real-delete-2026-10-08.json): afterBrowserDelete содержит interface:null, peerCount1 и собственный адрес на каждом CHR. Harness сохранил исходные идентификаторы own peers/IP и удалил только эти остатки, даже после исчезновения интерфейса. Финальный exit0, выбранные WG/peers/IP/routes/IPv4 Firewall поля совпали с baseline; ephemeral контейнер удалён, остались три основные службы. Это очистка теста, а не успешная приёмка стандартного удаления. Ключи не включены в публичные отчёты; WG revisions намеренно сохранены.
|
||||||
|
|
||||||
|
Локально добавлен backend/src/services/wireguard-delete.ts и подключён к DELETE route: идентификация интерфейса по rosId, чтение peers и IPv4 адресов до первой записи, отбор только связанных с именем/rosId объектов, удаление peers→addresses→interface, независимое перечитывание и ошибка при оставшихся объектах. При read failure запись не начинается; при промежуточной ошибке дальнейшее удаление прекращается, ошибка возвращается вместо ok. Успех и apply revision происходят только после проверки отсутствия объектов. Это последовательные RouterOS операции, не транзакция: частичный сбой может оставить частично удалённые данные, потребуется повтор/обновление. Текст подтверждения в WireGuard page теперь указывает связанные пиры и IP-адреса.
|
||||||
|
|
||||||
|
Проверки backend/src/services/wireguard-delete.test.ts —9/9: чужие объекты сохранены, связи по имени/rosId, encoded ID, ошибки всех предварительных чтений, неизвестный интерфейс, частичная ошибка/повтор, неподтверждённое удаление каждой группы. Profile UI tests wireguard-links.spec.ts --grep deletion/удал —2/2: подтверждение удаления интерфейса/пира, запрет повторного нажатия и повтор после API ошибки. Backend TypeScript, scoped frontend TypeScript (tmp/tsconfig-speed-check.json), ESLint изменённых файлов и ReUI checklist passed. Примитивы/таблицы не менялись.
|
||||||
|
|
||||||
|
Исправление пока локальное: удалённый backendbd3f996/frontendfd521f6 остаётся прежним. Следующий12.5.60 — production Docker build/deploy обеих частей, новая собственная WireGuard пара и обычное UI/API удаление без предварительного удаления peer/IP, независимая проверка отсутствия остатков и baseline, очистка fallback только own объектов. IPv6 address lifecycle, concurrency/multi-instance, Telegram/Portal и другие внешние ограничения не проверены. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
|
||||||
@@ -437,3 +437,15 @@ DELETE200/200, собственные GRE/IP/connected routes удалены; в
|
|||||||
[Первый проход](ux-ui/acceptance/wg-real-first-attempt-2026-10-08.json) подтвердил связность/UI, но cleanup harness получил DELETE400: Content-Type application/json был передан без тела. Это ошибка harness, не доказательство ошибки приложения. [Восстановительная очистка](ux-ui/acceptance/wg-first-cleanup-recovery-2026-10-08.json) через правильные DELETE проверила ownership comment/name и отсутствие own interfaces/peers/IP/routes. Baseline первого прохода был только в памяти и после выхода потерян; точная сверка первого baseline не заявляется. Harness исправлен, создана новая пара и повторён полный lifecycle/browser; итоговый exit0 и все выбранные baseline поля совпали.
|
[Первый проход](ux-ui/acceptance/wg-real-first-attempt-2026-10-08.json) подтвердил связность/UI, но cleanup harness получил DELETE400: Content-Type application/json был передан без тела. Это ошибка harness, не доказательство ошибки приложения. [Восстановительная очистка](ux-ui/acceptance/wg-first-cleanup-recovery-2026-10-08.json) через правильные DELETE проверила ownership comment/name и отсутствие own interfaces/peers/IP/routes. Baseline первого прохода был только в памяти и после выхода потерян; точная сверка первого baseline не заявляется. Harness исправлен, создана новая пара и повторён полный lifecycle/browser; итоговый exit0 и все выбранные baseline поля совпали.
|
||||||
|
|
||||||
В финальном cleanup собственные peers удалены API200/200, собственные IP явно удалены native API до удаления interfaces API200/200. Автоматическая очистка IP/peers при обычном удалении интерфейса НЕ проверена и остаётся следующим12.5.59. WireGuard/IP/routes/IPv4 Firewall выбранные настройки совпали с baseline; эфемерный контейнер удалён, работают только три основные Compose-службы. DB controls до/после servers2/speedHistory9/retention14/migrations9 совпали, backend healthy. WG revisions намеренно сохранены как история операций. Runtime backendbd3f996/frontendfd521f6 не менялся. Telegram/Portal/multi-instance и остальные внешние ограничения остаются открытыми. Локальный коммит без push.
|
В финальном cleanup собственные peers удалены API200/200, собственные IP явно удалены native API до удаления interfaces API200/200. Автоматическая очистка IP/peers при обычном удалении интерфейса НЕ проверена и остаётся следующим12.5.59. WireGuard/IP/routes/IPv4 Firewall выбранные настройки совпали с baseline; эфемерный контейнер удалён, работают только три основные Compose-службы. DB controls до/после servers2/speedHistory9/retention14/migrations9 совпали, backend healthy. WG revisions намеренно сохранены как история операций. Runtime backendbd3f996/frontendfd521f6 не менялся. Telegram/Portal/multi-instance и остальные внешние ограничения остаются открытыми. Локальный коммит без push.
|
||||||
|
|
||||||
|
## 12.5.59 — удаление WireGuard оставляло peer и IP; локальное исправление (2026-10-08)
|
||||||
|
|
||||||
|
[Production UI](ux-ui/acceptance/browser-wg-delete-2026-10-08.json): собственная новая пара mm-acceptance-wg-1791471219775, подтверждённые handshake/двусторонний Ping. Интерфейсы удалены через стандартные меню и AlertDialog приложения на обоих CHR (ПК/320px). DELETE200/200 закрыли диалоги, но независимое native чтение обнаружило на каждом устройстве оставшийся peer и собственный IPv4 адрес. Это подтверждённая ошибка backendbd3f996: route удалял только /interface/wireguard/id, RouterOS сохранил связанные записи.
|
||||||
|
|
||||||
|
[Native проверка и восстановительная очистка](ux-ui/acceptance/wg-real-delete-2026-10-08.json): afterBrowserDelete содержит interface:null, peerCount1 и собственный адрес на каждом CHR. Harness сохранил исходные идентификаторы own peers/IP и удалил только эти остатки, даже после исчезновения интерфейса. Финальный exit0, выбранные WG/peers/IP/routes/IPv4 Firewall поля совпали с baseline; ephemeral контейнер удалён, остались три основные службы. Это очистка теста, а не успешная приёмка стандартного удаления. Ключи не включены в публичные отчёты; WG revisions намеренно сохранены.
|
||||||
|
|
||||||
|
Локально добавлен backend/src/services/wireguard-delete.ts и подключён к DELETE route: идентификация интерфейса по rosId, чтение peers и IPv4 адресов до первой записи, отбор только связанных с именем/rosId объектов, удаление peers→addresses→interface, независимое перечитывание и ошибка при оставшихся объектах. При read failure запись не начинается; при промежуточной ошибке дальнейшее удаление прекращается, ошибка возвращается вместо ok. Успех и apply revision происходят только после проверки отсутствия объектов. Это последовательные RouterOS операции, не транзакция: частичный сбой может оставить частично удалённые данные, потребуется повтор/обновление. Текст подтверждения в WireGuard page теперь указывает связанные пиры и IP-адреса.
|
||||||
|
|
||||||
|
Проверки backend/src/services/wireguard-delete.test.ts —9/9: чужие объекты сохранены, связи по имени/rosId, encoded ID, ошибки всех предварительных чтений, неизвестный интерфейс, частичная ошибка/повтор, неподтверждённое удаление каждой группы. Profile UI tests wireguard-links.spec.ts --grep deletion/удал —2/2: подтверждение удаления интерфейса/пира, запрет повторного нажатия и повтор после API ошибки. Backend TypeScript, scoped frontend TypeScript (tmp/tsconfig-speed-check.json), ESLint изменённых файлов и ReUI checklist passed. Примитивы/таблицы не менялись.
|
||||||
|
|
||||||
|
Исправление пока локальное: удалённый backendbd3f996/frontendfd521f6 остаётся прежним. Следующий12.5.60 — production Docker build/deploy обеих частей, новая собственная WireGuard пара и обычное UI/API удаление без предварительного удаления peer/IP, независимая проверка отсутствия остатков и baseline, очистка fallback только own объектов. IPv6 address lifecycle, concurrency/multi-instance, Telegram/Portal и другие внешние ограничения не проверены. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"date": "2026-10-08",
|
||||||
|
"backendSource": "bd3f996",
|
||||||
|
"frontendSource": "fd521f6",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775",
|
||||||
|
"httpMocks": false,
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"serverId": 1,
|
||||||
|
"status": 200,
|
||||||
|
"interfaceAbsent": true,
|
||||||
|
"remainingPeerCount": 1,
|
||||||
|
"remainingAddresses": [
|
||||||
|
"198.18.255.241/30"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serverId": 2,
|
||||||
|
"status": 200,
|
||||||
|
"interfaceAbsent": true,
|
||||||
|
"remainingPeerCount": 1,
|
||||||
|
"remainingAddresses": [
|
||||||
|
"198.18.255.242/30"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pageErrors": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
{
|
||||||
|
"date": "2026-10-08",
|
||||||
|
"backendSource": "bd3f996",
|
||||||
|
"frontendSource": "fd521f6",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775",
|
||||||
|
"subnet": "198.18.255.240/30",
|
||||||
|
"listenPort": 51879,
|
||||||
|
"realRouterOs": true,
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/wireguard/interfaces",
|
||||||
|
"status": 201
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/wireguard/interfaces",
|
||||||
|
"status": 201
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/wireguard/peers",
|
||||||
|
"status": 201
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/wireguard/peers",
|
||||||
|
"status": 201
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "PATCH",
|
||||||
|
"path": "/api/wireguard/interfaces/1/*7",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "PATCH",
|
||||||
|
"path": "/api/wireguard/interfaces/1/*7",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/wireguard",
|
||||||
|
"status": 200
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pings": [
|
||||||
|
{
|
||||||
|
"serverId": 1,
|
||||||
|
"target": "198.18.255.242",
|
||||||
|
"interface": "mm-acceptance-wg-1791471219775",
|
||||||
|
"received": 3,
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"sent": "1",
|
||||||
|
"received": "1",
|
||||||
|
"packet-loss": "0",
|
||||||
|
"time": "55ms371us",
|
||||||
|
"avg-rtt": "55ms371us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sent": "2",
|
||||||
|
"received": "2",
|
||||||
|
"packet-loss": "0",
|
||||||
|
"time": "54ms567us",
|
||||||
|
"avg-rtt": "54ms969us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sent": "3",
|
||||||
|
"received": "3",
|
||||||
|
"packet-loss": "0",
|
||||||
|
"time": "54ms897us",
|
||||||
|
"avg-rtt": "54ms945us"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serverId": 2,
|
||||||
|
"target": "198.18.255.241",
|
||||||
|
"interface": "mm-acceptance-wg-1791471219775",
|
||||||
|
"received": 3,
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"sent": "1",
|
||||||
|
"received": "1",
|
||||||
|
"packet-loss": "0",
|
||||||
|
"time": "56ms179us",
|
||||||
|
"avg-rtt": "56ms179us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sent": "2",
|
||||||
|
"received": "2",
|
||||||
|
"packet-loss": "0",
|
||||||
|
"time": "55ms80us",
|
||||||
|
"avg-rtt": "55ms629us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sent": "3",
|
||||||
|
"received": "3",
|
||||||
|
"packet-loss": "0",
|
||||||
|
"time": "54ms776us",
|
||||||
|
"avg-rtt": "55ms345us"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cleanup": [
|
||||||
|
{
|
||||||
|
"serverId": 1,
|
||||||
|
"/interface/wireguard": true,
|
||||||
|
"/interface/wireguard/peers": true,
|
||||||
|
"/ip/address": true,
|
||||||
|
"/ip/route": true,
|
||||||
|
"/ip/firewall/filter": true,
|
||||||
|
"/ip/firewall/nat": true,
|
||||||
|
"/ip/firewall/mangle": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serverId": 2,
|
||||||
|
"/interface/wireguard": true,
|
||||||
|
"/interface/wireguard/peers": true,
|
||||||
|
"/ip/address": true,
|
||||||
|
"/ip/route": true,
|
||||||
|
"/ip/firewall/filter": true,
|
||||||
|
"/ip/firewall/nat": true,
|
||||||
|
"/ip/firewall/mangle": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nativeKeyGenerationConfirmed": true,
|
||||||
|
"connectedState": [
|
||||||
|
{
|
||||||
|
"serverId": 1,
|
||||||
|
"interface": {
|
||||||
|
"rosId": "*7",
|
||||||
|
"appId": "1:*7",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775",
|
||||||
|
"listenPort": "51879",
|
||||||
|
"mtu": "1420",
|
||||||
|
"running": "true",
|
||||||
|
"disabled": "false",
|
||||||
|
"userComment": "Temporary UX acceptance mm-acceptance-wg-1791471219775"
|
||||||
|
},
|
||||||
|
"addresses": [
|
||||||
|
"198.18.255.241/30"
|
||||||
|
],
|
||||||
|
"peers": [
|
||||||
|
{
|
||||||
|
"rosId": "*3",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775-peer",
|
||||||
|
"allowedAddresses": "198.18.255.242/32",
|
||||||
|
"endpoint": "104.165.244.7:51879",
|
||||||
|
"handshake": "0s",
|
||||||
|
"rx": "180",
|
||||||
|
"tx": "272",
|
||||||
|
"disabled": "false",
|
||||||
|
"userComment": "Temporary UX acceptance mm-acceptance-wg-1791471219775"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serverId": 2,
|
||||||
|
"interface": {
|
||||||
|
"rosId": "*3",
|
||||||
|
"appId": "2:*3",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775",
|
||||||
|
"listenPort": "51879",
|
||||||
|
"mtu": "1420",
|
||||||
|
"running": "true",
|
||||||
|
"disabled": "false",
|
||||||
|
"userComment": "Temporary UX acceptance mm-acceptance-wg-1791471219775"
|
||||||
|
},
|
||||||
|
"addresses": [
|
||||||
|
"198.18.255.242/30"
|
||||||
|
],
|
||||||
|
"peers": [
|
||||||
|
{
|
||||||
|
"rosId": "*1",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775-peer",
|
||||||
|
"allowedAddresses": "198.18.255.241/32",
|
||||||
|
"endpoint": "194.226.121.150:51879",
|
||||||
|
"handshake": "0s",
|
||||||
|
"rx": "124",
|
||||||
|
"tx": "180",
|
||||||
|
"disabled": "false",
|
||||||
|
"userComment": "Temporary UX acceptance mm-acceptance-wg-1791471219775"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handshakeConfirmed": true,
|
||||||
|
"bidirectionalPingPassed": true,
|
||||||
|
"catalogMatchesNative": true,
|
||||||
|
"afterBrowserDelete": [
|
||||||
|
{
|
||||||
|
"serverId": 1,
|
||||||
|
"interface": null,
|
||||||
|
"addresses": [
|
||||||
|
"198.18.255.241/30"
|
||||||
|
],
|
||||||
|
"peers": [
|
||||||
|
{
|
||||||
|
"rosId": "*3",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775-peer",
|
||||||
|
"allowedAddresses": "198.18.255.242/32",
|
||||||
|
"endpoint": "104.165.244.7:51879",
|
||||||
|
"handshake": "34s",
|
||||||
|
"rx": "788",
|
||||||
|
"tx": "1040",
|
||||||
|
"disabled": "false",
|
||||||
|
"userComment": "Temporary UX acceptance mm-acceptance-wg-1791471219775"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serverId": 2,
|
||||||
|
"interface": null,
|
||||||
|
"addresses": [
|
||||||
|
"198.18.255.242/30"
|
||||||
|
],
|
||||||
|
"peers": [
|
||||||
|
{
|
||||||
|
"rosId": "*1",
|
||||||
|
"name": "mm-acceptance-wg-1791471219775-peer",
|
||||||
|
"allowedAddresses": "198.18.255.241/32",
|
||||||
|
"endpoint": "194.226.121.150:51879",
|
||||||
|
"handshake": "36s",
|
||||||
|
"rx": "892",
|
||||||
|
"tx": "788",
|
||||||
|
"disabled": "false",
|
||||||
|
"userComment": "Temporary UX acceptance mm-acceptance-wg-1791471219775"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"limits": [
|
||||||
|
"Only own WireGuard interface/peer/IP and connected route changed; no default routes/firewall changes",
|
||||||
|
"Own IP addresses explicitly deleted via native API before interface deletion; automatic address cleanup was not tested",
|
||||||
|
"Private/public/preshared keys omitted from report; native generation and peer association checked in memory",
|
||||||
|
"Handshake and short ICMP connectivity, not throughput, RBAC or interrupted mutation",
|
||||||
|
"WireGuard audit revisions intentionally retained"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in new issue
Block a user