chore(test): подготовить проверку реального продления сертификата
This commit is contained in:
1 parent
3d23ae4be4
commit
37a9c828d3
10 files changed
+207
-9
No files matched your search
@@ -0,0 +1,71 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import tls from 'node:tls';
|
||||||
|
import { X509Certificate } from 'node:crypto';
|
||||||
|
import { pathToFileURL } from 'node:url';
|
||||||
|
|
||||||
|
const fingerprint = value => {
|
||||||
|
assert.equal(typeof value, 'string', 'Fingerprint is required');
|
||||||
|
const normalized = value.replaceAll(':', '').toLowerCase();
|
||||||
|
assert(/^[a-f0-9]{64}$/.test(normalized), 'Expected SHA-256 fingerprint');
|
||||||
|
return normalized;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function compareRenewal(before, after) {
|
||||||
|
for (const sample of [before, after]) {
|
||||||
|
assert(/^mmt253-[a-f0-9]{8}\.pngs\.top$/.test(sample.fqdn), 'Only the prepared exact test domain is permitted');
|
||||||
|
assert.equal(sample.remoteAddress, '104.165.244.7');
|
||||||
|
assert.equal(sample.authorized, true);
|
||||||
|
assert.equal(sample.hostnameMatched, true);
|
||||||
|
assert.equal(sample.nativePrivateKey, true);
|
||||||
|
assert.equal(sample.nativeName, sample.certName);
|
||||||
|
assert.equal(sample.certName, sample.fqdn.replace('.pngs.top', ''));
|
||||||
|
assert.equal(fingerprint(sample.nativeFingerprint256), fingerprint(sample.fingerprint256), 'Native leaf must match served TLS');
|
||||||
|
assert(Number.isFinite(Date.parse(sample.validUntil)), 'Expiry is required');
|
||||||
|
assert(Number.isFinite(Date.parse(sample.sampledAt)), 'Sample time is required');
|
||||||
|
assert(Date.parse(sample.validUntil) > Date.parse(sample.sampledAt), 'Certificate is expired');
|
||||||
|
}
|
||||||
|
assert.equal(after.fqdn, before.fqdn);
|
||||||
|
assert.equal(after.certName, before.certName);
|
||||||
|
assert.notEqual(fingerprint(after.fingerprint256), fingerprint(before.fingerprint256), 'Old certificate is still being served');
|
||||||
|
assert(Date.parse(after.sampledAt) >= Date.parse(before.sampledAt));
|
||||||
|
assert(Date.parse(after.validUntil) > Date.parse(after.sampledAt), 'New certificate is expired');
|
||||||
|
// A second issuance on the same day need not extend expiry by a full day.
|
||||||
|
return { fingerprintChanged: true, nativeAndTlsMatch: true, trustedHostnameMatch: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sample(fixture) {
|
||||||
|
assert(/^mmt253-[a-f0-9]{8}\.pngs\.top$/.test(fixture.fqdn));
|
||||||
|
assert.equal(fixture.certName, fixture.fqdn.replace('.pngs.top', ''));
|
||||||
|
assert.equal(fixture.nativePrivateKey, true);
|
||||||
|
fingerprint(fixture.nativeFingerprint256);
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
const socket = tls.connect({ host: '104.165.244.7', port: 443, servername: fixture.fqdn, rejectUnauthorized: true });
|
||||||
|
socket.setTimeout(15000, () => socket.destroy(new Error('TLS acceptance timeout')));
|
||||||
|
socket.once('error', reject);
|
||||||
|
socket.once('secureConnect', () => {
|
||||||
|
try {
|
||||||
|
assert.equal(socket.authorized, true);
|
||||||
|
const cert = new X509Certificate(socket.getPeerCertificate().raw);
|
||||||
|
assert(cert.checkHost(fixture.fqdn), 'Hostname mismatch');
|
||||||
|
assert(Date.parse(cert.validTo) > Date.now(), 'Certificate is expired');
|
||||||
|
assert.equal(fingerprint(cert.fingerprint256), fingerprint(fixture.nativeFingerprint256), 'Native leaf does not match TLS');
|
||||||
|
resolve({ sampledAt: new Date().toISOString(), fqdn: fixture.fqdn, certName: fixture.certName,
|
||||||
|
remoteAddress: socket.remoteAddress, authorized: socket.authorized, hostnameMatched: true,
|
||||||
|
protocol: socket.getProtocol(), fingerprint256: cert.fingerprint256,
|
||||||
|
validFrom: cert.validFrom, validUntil: cert.validTo,
|
||||||
|
nativeName: fixture.certName, nativePrivateKey: true, nativeFingerprint256: fixture.nativeFingerprint256 });
|
||||||
|
} catch (error) { reject(error); } finally { socket.end(); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||||
|
const [mode, input, output] = process.argv.slice(2);
|
||||||
|
assert(input && output && ['sample', 'compare'].includes(mode), 'Usage: sample native-summary.json output.json | compare samples.json output.json');
|
||||||
|
assert(!fs.existsSync(output), 'Never overwrite acceptance evidence');
|
||||||
|
const data = JSON.parse(fs.readFileSync(input, 'utf8'));
|
||||||
|
const result = mode === 'sample' ? await sample(data) : compareRenewal(data.before, data.after);
|
||||||
|
fs.writeFileSync(output, JSON.stringify(result, null, 2) + '\n', { flag: 'wx' });
|
||||||
|
console.log(mode === 'sample' ? 'Trusted TLS/native fingerprint sample saved' : 'Renewal fingerprint comparison passed');
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { compareRenewal } from './acme-renew-tls.mjs';
|
||||||
|
const before = { fqdn: 'mmt253-a1b2c3d4.pngs.top', certName: 'mmt253-a1b2c3d4', nativeName: 'mmt253-a1b2c3d4',
|
||||||
|
remoteAddress: '104.165.244.7', authorized: true, hostnameMatched: true, nativePrivateKey: true,
|
||||||
|
fingerprint256: 'a'.repeat(64), nativeFingerprint256: 'a'.repeat(64), sampledAt: '2026-10-14T12:00:00Z', validUntil: '2027-01-12T12:00:00Z' };
|
||||||
|
const after = { ...before, fingerprint256: 'b'.repeat(64), nativeFingerprint256: 'b'.repeat(64), sampledAt: '2026-10-14T12:01:00Z' };
|
||||||
|
assert.equal(compareRenewal(before, after).fingerprintChanged, true);
|
||||||
|
for (const patch of [{ fingerprint256: before.fingerprint256, nativeFingerprint256: before.nativeFingerprint256 },
|
||||||
|
{ nativeFingerprint256: before.nativeFingerprint256 }, { authorized: false }, { hostnameMatched: false },
|
||||||
|
{ nativePrivateKey: false }, { nativeName: 'another' }, { fqdn: 'other.pngs.top' },
|
||||||
|
{ remoteAddress: '194.226.121.150' }, { validUntil: 'bad' }, { validUntil: '2026-10-13T12:00:00Z' },
|
||||||
|
{ sampledAt: '2026-10-14T11:00:00Z' }]) assert.throws(() => compareRenewal(before, { ...after, ...patch }));
|
||||||
|
console.log('Renewal acceptance comparison: changed leaf passes; 11 false-success cases rejected. No network or CA calls.');
|
||||||
@@ -13,3 +13,19 @@
|
|||||||
Выданный публичный сертификат CA не объявляется отозванным: экземпляры и ключевые файлы на CHR удалены, DNS очищен; запись о выпуске сохраняется у CA. Это не тест автоматического renewal, CA revocation или нескольких backend.
|
Выданный публичный сертификат CA не объявляется отозванным: экземпляры и ключевые файлы на CHR удалены, DNS очищен; запись о выпуске сохраняется у CA. Это не тест автоматического renewal, CA revocation или нескольких backend.
|
||||||
|
|
||||||
Протоколы: [UI](../docs/ux-ui/acceptance/acme250-live-ui.json), [TLS](../docs/ux-ui/acceptance/acme250-tls.json), [DNS](../docs/ux-ui/acceptance/acme250-cloudflare.json), [native/cleanup](../docs/ux-ui/acceptance/acme250-native.json).
|
Протоколы: [UI](../docs/ux-ui/acceptance/acme250-live-ui.json), [TLS](../docs/ux-ui/acceptance/acme250-tls.json), [DNS](../docs/ux-ui/acceptance/acme250-cloudflare.json), [native/cleanup](../docs/ux-ui/acceptance/acme250-native.json).
|
||||||
|
|
||||||
|
## Подготовка повторной выдачи / renewal — блок253 (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен конкретный домен `mmt253-8e62a941.pngs.top`, certName `mmt253-8e62a941`, CHR `104.165.244.7` (server2). Это обычное имя без wildcard. Этот раздел описывает следующий тест; выдача и продление253 ещё не запускались. Первичная выдача250 не доказывает замену сертификата при повторном импорте. HTTP ACK и terminal job сами по себе также не доказывают, какой leaf обслуживает TLS.
|
||||||
|
|
||||||
|
1. Перед изменениями снять свежий приватный baseline: native export, certificates/files/services; SQL ACME и renewal settings, список managed targets/jobs; scheduler state. Подтвердить отсутствие любых других managed targets/active jobs и DNS записей на обоих точных именах. Если они появились — остановиться до мутации. Не использовать удалённый baseline250.
|
||||||
|
2. Временно остановить автоматический certificates_renew через его настройки и дождаться отсутствия текущего запуска. Сохранить исходные настройки целиком. Не запускать несколько экземпляров collector. Настроить тестовый Cloudflare token и выполнить первый UI выпуск с новым requestId. Публично сохранить только terminal job/protocol и native metadata без секретов.
|
||||||
|
3. По аутентифицированному RouterOS чтению выбрать ровно один собственный leaf с exact name/CN, private-key=true и отпечатком; снять served TLS с SNI/обычной проверкой доверия. Если native fingerprint не SHA-256, сначала экспортировать только публичный сертификат и вычислить SHA-256 через X509Certificate; не интерпретировать другой алгоритм как SHA-256. Изолированная сводка для helper содержит только fqdn/certName/nativePrivateKey/nativeFingerprint256.
|
||||||
|
4. Read-only helper `node backend/scripts/acceptance/acme-renew-tls.mjs sample native-summary.json before.json` подключается только к104.165.244.7:443 с точным SNI, rejectUnauthorized=true и15s timeout. Требует совпадения native и TLS SHA-256, private key и hostname. Существующий output не перезаписывается. Этот helper ничего не выпускает и не меняет RouterOS/DNS.
|
||||||
|
5. Для реального collector renewal подтвердить канонический срок/статус leaf по state. Не менять даты на CHR и не обходить unknown guard252. Если RouterOS дата не распознаётся, записать препятствие и не запускать повторную выдачу. Для известного срока при выключенном renewal подготовить порог90 дней и интервал не менее3600s, подтвердить единственный собственный target. Затем один PUT enabled=true запускает certificates_renew через refreshScheduler немедленно: отдельный run-now НЕ отправлять. После terminal сразу выключить renewal до следующего интервала. Сохранить ID созданной scheduler-задачи; при неизвестном ACK проверять тот же ID, новый run не отправлять. Проверить source=scheduler, matching context, terminal done и snapshot renewed1/errors0.
|
||||||
|
6. Снять after.json тем же helper и сравнить `node backend/scripts/acceptance/acme-renew-tls.mjs compare samples.json comparison.json`, где samples.json содержит before/after. Новый SHA-256 должен отличаться от первого, native должен совпасть с served TLS. Не требовать увеличения expiry на целый день: обе выдачи могут быть в один день. Проверить оба назначения www-ssl/api-ssl и HTTPS REST с обычным доверием. Если job done, а TLS leaf прежний, это ошибка приёмки; не удалять первый leaf ради получения ложного успеха.
|
||||||
|
7. Независимо от результата остановить own renewal, вернуть исходные SSL сервисы, удалить только собственные exact cert IDs/fingerprints/PEM файлы/job IDs; вернуть ACME/renew settings целиком. Удалять только DNS записи с проверенными exact name/type/content/ID, не чужие записи. Подтвердить исходные коллекции, normalized export, settings и0 own DNS; удалить private baseline/token. Контрольный194.226.121.150 не менять, пароли не менять, перезагрузки не нужны.
|
||||||
|
|
||||||
|
Для этих двух выдач и повторного назначения SSL необходимо согласие на конкретный сценарий. Разрешение250 относилось к уже завершённому тесту. До согласия выполняются только подготовка/чтение. Полная регрессия и Docker build для изменения лишь ручного acceptance helper не нужны; comparator проверяется отдельно. CA revocation и multi-instance здесь не принимаются.
|
||||||
|
|
||||||
|
Нормативная справка для native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates). Документация не гарантирует успех повторного импорта в текущем приложении; именно это предстоит измерить.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: протокол внешней приёмки 12.5
|
# UX/UI: протокол внешней приёмки 12.5
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14: 252 — сертификаты используют strict-ID/enabled guards; renewal больше не объявляет failed/pending успешным и не подменяет неизвестный срок нулём. Восемь профильных scripts и 39 API/SQL checks прошли, own DB/role удалены. Backend ux-certificates252/frontend ux-certificates251 healthy, source526/dist1080 matched. Реальный Portal/read1440/390: оба CHR без ошибок, writes0. Следующий253 — подготовка реальной повторной выдачи/renewal и безопасного сравнения сертификата/TLS; эта приёмка ещё открыта. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14: 253 — подготовлена реальная приёмка renewal для exact mmt253-8e62a941.pngs.top на CHR104, read-only DNS empty/оба REST200. TLS/native SHA-256 comparator: positive и11 false-success отказов passed, syntax/lint passed. Никаких выдач/изменений253 не запускали. Runtime backend ux-certificates252/frontend ux-certificates251. Далее согласовать два выпуска/renewal с назначением SSL и полным откатом по deploy/TEST-ACME.md; этап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).
|
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).
|
||||||
|
|
||||||
@@ -18,6 +18,18 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro
|
|||||||
|
|
||||||
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
||||||
|
|
||||||
|
## 12.5.253 — подготовка проверки реальной замены сертификата при renewal (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен exact mmt253-8e62a941.pngs.top/certName mmt253-8e62a941 на CHR104/server2. Read-only preflight с Debian: точный FQDN и challenge name имеют0 Cloudflare records, оба CHR REST200 с прежними паролями. Ни DNS/settings/native writes, ни ACME orders не выполнялись. Это не свежий приватный baseline для будущей мутации: его нужно снять непосредственно перед запуском.
|
||||||
|
|
||||||
|
Новый ручной helper backend/scripts/acceptance/acme-renew-tls.mjs делает bounded15s TLS к фиксированному104:443 с exact SNI и rejectUnauthorized=true. Сверяет hostname, native SHA-256/private-key/name и served leaf. Compare требует изменения SHA-256 после повторного выпуска, совпадения native/TLS, корректных дат; output не перезаписывается. Ввод содержит только публичную native сводку, не keys/passwords. Один positive и11 negative comparator случаев passed без сети/CA; syntax и scoped ESLint passed. Это проверка проверяющего инструмента, не реального renewal. Native fingerprint другого алгоритма сначала пересчитывается из публичного PEM, не угадывается.
|
||||||
|
|
||||||
|
Процедура в [TEST-ACME](../deploy/TEST-ACME.md) включает свежий private baseline/settings/managed targets, единственный собственный target, первый UI выпуск, initial TLS, canonical date guard252 и один scheduler renewal. Code review пути settings выявил важное условие: PUT enabled=true вызывает refreshScheduler с немедленным запуском, поэтому дополнительный run-now запрещён. После terminal renewal выключается до следующего интервала. Если дата unknown, повторный выпуск не запускается и ограничение фиксируется. Job done без нового served fingerprint считается провалом, старый leaf не удаляется ради прохождения теста.
|
||||||
|
|
||||||
|
Откат описан по exact IDs/fingerprints/files/record content и исходным settings/services/normalized export, контрольный CHR194 не меняется, перезагрузки/смена паролей не нужны. Публичная CA выдача не объявляется revoked. Справка native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates); факт замены проверяется измерением, документация его не подтверждает для текущего приложения.
|
||||||
|
|
||||||
|
Production код не менялся, Docker build/deploy не нужен, backend ux-certificates252/frontend ux-certificates251 сохранены. Следующий шаг — согласование конкретных двух выдач/renewal с включением www-ssl/api-ssl и полным откатом; разрешение250 относилось к уже завершённому выпуску. До согласия только подготовка/чтение. Реальное renewal, CA revoke и multi-instance остаются открыты.
|
||||||
|
|
||||||
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
||||||
|
|
||||||
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
||||||
|
|||||||
+13
-1
@@ -1,9 +1,21 @@
|
|||||||
# План реализации UX/UI по пятичасовым окнам
|
# План реализации UX/UI по пятичасовым окнам
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14: 252 — сертификаты используют strict-ID/enabled guards; renewal больше не объявляет failed/pending успешным и не подменяет неизвестный срок нулём. Восемь профильных scripts и 39 API/SQL checks прошли, own DB/role удалены. Backend ux-certificates252/frontend ux-certificates251 healthy, source526/dist1080 matched. Реальный Portal/read1440/390: оба CHR без ошибок, writes0. Следующий253 — подготовка реальной повторной выдачи/renewal и безопасного сравнения сертификата/TLS; эта приёмка ещё открыта. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14: 253 — подготовлена реальная приёмка renewal для exact mmt253-8e62a941.pngs.top на CHR104, read-only DNS empty/оба REST200. TLS/native SHA-256 comparator: positive и11 false-success отказов passed, syntax/lint passed. Никаких выдач/изменений253 не запускали. Runtime backend ux-certificates252/frontend ux-certificates251. Далее согласовать два выпуска/renewal с назначением SSL и полным откатом по deploy/TEST-ACME.md; этап12.5 открыт.
|
||||||
|
|
||||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-14. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-14. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||||
|
|
||||||
|
## 12.5.253 — подготовка проверки реальной замены сертификата при renewal (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен exact mmt253-8e62a941.pngs.top/certName mmt253-8e62a941 на CHR104/server2. Read-only preflight с Debian: точный FQDN и challenge name имеют0 Cloudflare records, оба CHR REST200 с прежними паролями. Ни DNS/settings/native writes, ни ACME orders не выполнялись. Это не свежий приватный baseline для будущей мутации: его нужно снять непосредственно перед запуском.
|
||||||
|
|
||||||
|
Новый ручной helper backend/scripts/acceptance/acme-renew-tls.mjs делает bounded15s TLS к фиксированному104:443 с exact SNI и rejectUnauthorized=true. Сверяет hostname, native SHA-256/private-key/name и served leaf. Compare требует изменения SHA-256 после повторного выпуска, совпадения native/TLS, корректных дат; output не перезаписывается. Ввод содержит только публичную native сводку, не keys/passwords. Один positive и11 negative comparator случаев passed без сети/CA; syntax и scoped ESLint passed. Это проверка проверяющего инструмента, не реального renewal. Native fingerprint другого алгоритма сначала пересчитывается из публичного PEM, не угадывается.
|
||||||
|
|
||||||
|
Процедура в [TEST-ACME](../deploy/TEST-ACME.md) включает свежий private baseline/settings/managed targets, единственный собственный target, первый UI выпуск, initial TLS, canonical date guard252 и один scheduler renewal. Code review пути settings выявил важное условие: PUT enabled=true вызывает refreshScheduler с немедленным запуском, поэтому дополнительный run-now запрещён. После terminal renewal выключается до следующего интервала. Если дата unknown, повторный выпуск не запускается и ограничение фиксируется. Job done без нового served fingerprint считается провалом, старый leaf не удаляется ради прохождения теста.
|
||||||
|
|
||||||
|
Откат описан по exact IDs/fingerprints/files/record content и исходным settings/services/normalized export, контрольный CHR194 не меняется, перезагрузки/смена паролей не нужны. Публичная CA выдача не объявляется revoked. Справка native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates); факт замены проверяется измерением, документация его не подтверждает для текущего приложения.
|
||||||
|
|
||||||
|
Production код не менялся, Docker build/deploy не нужен, backend ux-certificates252/frontend ux-certificates251 сохранены. Следующий шаг — согласование конкретных двух выдач/renewal с включением www-ssl/api-ssl и полным откатом; разрешение250 относилось к уже завершённому выпуску. До согласия только подготовка/чтение. Реальное renewal, CA revoke и multi-instance остаются открыты.
|
||||||
|
|
||||||
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
||||||
|
|
||||||
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
||||||
|
|||||||
+14
-2
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: журнал реализации
|
# UX/UI: журнал реализации
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14: 252 — сертификаты используют strict-ID/enabled guards; renewal больше не объявляет failed/pending успешным и не подменяет неизвестный срок нулём. Восемь профильных scripts и 39 API/SQL checks прошли, own DB/role удалены. Backend ux-certificates252/frontend ux-certificates251 healthy, source526/dist1080 matched. Реальный Portal/read1440/390: оба CHR без ошибок, writes0. Следующий253 — подготовка реальной повторной выдачи/renewal и безопасного сравнения сертификата/TLS; эта приёмка ещё открыта. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14: 253 — подготовлена реальная приёмка renewal для exact mmt253-8e62a941.pngs.top на CHR104, read-only DNS empty/оба REST200. TLS/native SHA-256 comparator: positive и11 false-success отказов passed, syntax/lint passed. Никаких выдач/изменений253 не запускали. Runtime backend ux-certificates252/frontend ux-certificates251. Далее согласовать два выпуска/renewal с назначением SSL и полным откатом по deploy/TEST-ACME.md; этап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).
|
||||||
|
|
||||||
@@ -36,7 +36,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–252 в записанных scopes. Runtime backend ux-certificates252/frontend ux-certificates251. Общая регрессия249 и профиль сертификатов252 прошли; реальный renewal остаётся открытым. |
|
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная12.3.83; внешняя12.5 открыта, завершённые блоки1–253 (253 — подготовка) в записанных scopes. Runtime backend ux-certificates252/frontend ux-certificates251. Общая регрессия249 и профиль сертификатов252 прошли; реальный renewal остаётся открытым. |
|
||||||
|
|
||||||
|
## 12.5.253 — подготовка проверки реальной замены сертификата при renewal (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен exact mmt253-8e62a941.pngs.top/certName mmt253-8e62a941 на CHR104/server2. Read-only preflight с Debian: точный FQDN и challenge name имеют0 Cloudflare records, оба CHR REST200 с прежними паролями. Ни DNS/settings/native writes, ни ACME orders не выполнялись. Это не свежий приватный baseline для будущей мутации: его нужно снять непосредственно перед запуском.
|
||||||
|
|
||||||
|
Новый ручной helper backend/scripts/acceptance/acme-renew-tls.mjs делает bounded15s TLS к фиксированному104:443 с exact SNI и rejectUnauthorized=true. Сверяет hostname, native SHA-256/private-key/name и served leaf. Compare требует изменения SHA-256 после повторного выпуска, совпадения native/TLS, корректных дат; output не перезаписывается. Ввод содержит только публичную native сводку, не keys/passwords. Один positive и11 negative comparator случаев passed без сети/CA; syntax и scoped ESLint passed. Это проверка проверяющего инструмента, не реального renewal. Native fingerprint другого алгоритма сначала пересчитывается из публичного PEM, не угадывается.
|
||||||
|
|
||||||
|
Процедура в [TEST-ACME](../deploy/TEST-ACME.md) включает свежий private baseline/settings/managed targets, единственный собственный target, первый UI выпуск, initial TLS, canonical date guard252 и один scheduler renewal. Code review пути settings выявил важное условие: PUT enabled=true вызывает refreshScheduler с немедленным запуском, поэтому дополнительный run-now запрещён. После terminal renewal выключается до следующего интервала. Если дата unknown, повторный выпуск не запускается и ограничение фиксируется. Job done без нового served fingerprint считается провалом, старый leaf не удаляется ради прохождения теста.
|
||||||
|
|
||||||
|
Откат описан по exact IDs/fingerprints/files/record content и исходным settings/services/normalized export, контрольный CHR194 не меняется, перезагрузки/смена паролей не нужны. Публичная CA выдача не объявляется revoked. Справка native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates); факт замены проверяется измерением, документация его не подтверждает для текущего приложения.
|
||||||
|
|
||||||
|
Production код не менялся, Docker build/deploy не нужен, backend ux-certificates252/frontend ux-certificates251 сохранены. Следующий шаг — согласование конкретных двух выдач/renewal с включением www-ssl/api-ssl и полным откатом; разрешение250 относилось к уже завершённому выпуску. До согласия только подготовка/чтение. Реальное renewal, CA revoke и multi-instance остаются открыты.
|
||||||
|
|
||||||
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
# Оставшаяся внешняя приёмка — 2026-10-14
|
# Оставшаяся внешняя приёмка — 2026-10-14
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14: 252 — сертификаты используют strict-ID/enabled guards; renewal больше не объявляет failed/pending успешным и не подменяет неизвестный срок нулём. Восемь профильных scripts и 39 API/SQL checks прошли, own DB/role удалены. Backend ux-certificates252/frontend ux-certificates251 healthy, source526/dist1080 matched. Реальный Portal/read1440/390: оба CHR без ошибок, writes0. Следующий253 — подготовка реальной повторной выдачи/renewal и безопасного сравнения сертификата/TLS; эта приёмка ещё открыта. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14: 253 — подготовлена реальная приёмка renewal для exact mmt253-8e62a941.pngs.top на CHR104, read-only DNS empty/оба REST200. TLS/native SHA-256 comparator: positive и11 false-success отказов passed, syntax/lint passed. Никаких выдач/изменений253 не запускали. Runtime backend ux-certificates252/frontend ux-certificates251. Далее согласовать два выпуска/renewal с назначением SSL и полным откатом по deploy/TEST-ACME.md; этап12.5 открыт.
|
||||||
|
|
||||||
Это актуальная матрица после 12.5.252. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
Это актуальная матрица после 12.5.253. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||||
|
|
||||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-certificates252`, frontend `ux-certificates251`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-certificates252`, frontend `ux-certificates251`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||||
|
|
||||||
|
## 12.5.253 — подготовка проверки реальной замены сертификата при renewal (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен exact mmt253-8e62a941.pngs.top/certName mmt253-8e62a941 на CHR104/server2. Read-only preflight с Debian: точный FQDN и challenge name имеют0 Cloudflare records, оба CHR REST200 с прежними паролями. Ни DNS/settings/native writes, ни ACME orders не выполнялись. Это не свежий приватный baseline для будущей мутации: его нужно снять непосредственно перед запуском.
|
||||||
|
|
||||||
|
Новый ручной helper backend/scripts/acceptance/acme-renew-tls.mjs делает bounded15s TLS к фиксированному104:443 с exact SNI и rejectUnauthorized=true. Сверяет hostname, native SHA-256/private-key/name и served leaf. Compare требует изменения SHA-256 после повторного выпуска, совпадения native/TLS, корректных дат; output не перезаписывается. Ввод содержит только публичную native сводку, не keys/passwords. Один positive и11 negative comparator случаев passed без сети/CA; syntax и scoped ESLint passed. Это проверка проверяющего инструмента, не реального renewal. Native fingerprint другого алгоритма сначала пересчитывается из публичного PEM, не угадывается.
|
||||||
|
|
||||||
|
Процедура в [TEST-ACME](../deploy/TEST-ACME.md) включает свежий private baseline/settings/managed targets, единственный собственный target, первый UI выпуск, initial TLS, canonical date guard252 и один scheduler renewal. Code review пути settings выявил важное условие: PUT enabled=true вызывает refreshScheduler с немедленным запуском, поэтому дополнительный run-now запрещён. После terminal renewal выключается до следующего интервала. Если дата unknown, повторный выпуск не запускается и ограничение фиксируется. Job done без нового served fingerprint считается провалом, старый leaf не удаляется ради прохождения теста.
|
||||||
|
|
||||||
|
Откат описан по exact IDs/fingerprints/files/record content и исходным settings/services/normalized export, контрольный CHR194 не меняется, перезагрузки/смена паролей не нужны. Публичная CA выдача не объявляется revoked. Справка native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates); факт замены проверяется измерением, документация его не подтверждает для текущего приложения.
|
||||||
|
|
||||||
|
Production код не менялся, Docker build/deploy не нужен, backend ux-certificates252/frontend ux-certificates251 сохранены. Следующий шаг — согласование конкретных двух выдач/renewal с включением www-ssl/api-ssl и полным откатом; разрешение250 относилось к уже завершённому выпуску. До согласия только подготовка/чтение. Реальное renewal, CA revoke и multi-instance остаются открыты.
|
||||||
|
|
||||||
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
||||||
|
|
||||||
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
||||||
@@ -254,7 +266,7 @@ Portal offline JWT действует доexp после logout/role change; э
|
|||||||
|
|
||||||
## Следующая последовательность — 2026-10-14
|
## Следующая последовательность — 2026-10-14
|
||||||
|
|
||||||
1. **Сертификаты253:** первичный issuance250, UX/Stepper251 и guards/result252 приняты. Подготовить реальную повторную выдачу/renewal с fingerprint/TLS и полным откатом. CA revoke/remote publishing/multi-instance остаются отдельными scope.
|
1. **Сертификаты254:** подготовка253 завершена; согласовать и выполнить first issuance + scheduler renewal exact mmt253-8e62a941.pngs.top с native/TLS fingerprint и откатом. Реальный renewal пока не принят. CA revoke/remote publishing/multi-instance — отдельные scopes.
|
||||||
2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания.
|
2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания.
|
||||||
3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций.
|
3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций.
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -1,6 +1,6 @@
|
|||||||
# Этап 12: итоговая приёмка UX/UI
|
# Этап 12: итоговая приёмка UX/UI
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14: 252 — сертификаты используют strict-ID/enabled guards; renewal больше не объявляет failed/pending успешным и не подменяет неизвестный срок нулём. Восемь профильных scripts и 39 API/SQL checks прошли, own DB/role удалены. Backend ux-certificates252/frontend ux-certificates251 healthy, source526/dist1080 matched. Реальный Portal/read1440/390: оба CHR без ошибок, writes0. Следующий253 — подготовка реальной повторной выдачи/renewal и безопасного сравнения сертификата/TLS; эта приёмка ещё открыта. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14: 253 — подготовлена реальная приёмка renewal для exact mmt253-8e62a941.pngs.top на CHR104, read-only DNS empty/оба REST200. TLS/native SHA-256 comparator: positive и11 false-success отказов passed, syntax/lint passed. Никаких выдач/изменений253 не запускали. Runtime backend ux-certificates252/frontend ux-certificates251. Далее согласовать два выпуска/renewal с назначением SSL и полным откатом по deploy/TEST-ACME.md; этап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.
|
||||||
|
|
||||||
@@ -4152,6 +4152,18 @@ Real Portal/browser API, provider local verified: создан один job ро
|
|||||||
Runtime backend ux-backup234/frontend ux-routing218 healthy; новое application image для volume-only fix не требовалось. Пароли CHR не менялись, S3 mutations0 в235, configs body/JWT не опубликованы, private local manifest удалён. Исходные10 missing local files не восстановлены и records не удалены. Force-recreate — не host reboot/power loss/fsync/DR приёмка. Далее236 — UX недоступных local files, затем version retention границы и оставшиеся7 группы матрицы; multi-instance guard не принимается. Этап12.5 открыт.
|
Runtime backend ux-backup234/frontend ux-routing218 healthy; новое application image для volume-only fix не требовалось. Пароли CHR не менялись, S3 mutations0 в235, configs body/JWT не опубликованы, private local manifest удалён. Исходные10 missing local files не восстановлены и records не удалены. Force-recreate — не host reboot/power loss/fsync/DR приёмка. Далее236 — UX недоступных local files, затем version retention границы и оставшиеся7 группы матрицы; multi-instance guard не принимается. Этап12.5 открыт.
|
||||||
|
|
||||||
|
|
||||||
|
## 12.5.253 — подготовка проверки реальной замены сертификата при renewal (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен exact mmt253-8e62a941.pngs.top/certName mmt253-8e62a941 на CHR104/server2. Read-only preflight с Debian: точный FQDN и challenge name имеют0 Cloudflare records, оба CHR REST200 с прежними паролями. Ни DNS/settings/native writes, ни ACME orders не выполнялись. Это не свежий приватный baseline для будущей мутации: его нужно снять непосредственно перед запуском.
|
||||||
|
|
||||||
|
Новый ручной helper backend/scripts/acceptance/acme-renew-tls.mjs делает bounded15s TLS к фиксированному104:443 с exact SNI и rejectUnauthorized=true. Сверяет hostname, native SHA-256/private-key/name и served leaf. Compare требует изменения SHA-256 после повторного выпуска, совпадения native/TLS, корректных дат; output не перезаписывается. Ввод содержит только публичную native сводку, не keys/passwords. Один positive и11 negative comparator случаев passed без сети/CA; syntax и scoped ESLint passed. Это проверка проверяющего инструмента, не реального renewal. Native fingerprint другого алгоритма сначала пересчитывается из публичного PEM, не угадывается.
|
||||||
|
|
||||||
|
Процедура в [TEST-ACME](../deploy/TEST-ACME.md) включает свежий private baseline/settings/managed targets, единственный собственный target, первый UI выпуск, initial TLS, canonical date guard252 и один scheduler renewal. Code review пути settings выявил важное условие: PUT enabled=true вызывает refreshScheduler с немедленным запуском, поэтому дополнительный run-now запрещён. После terminal renewal выключается до следующего интервала. Если дата unknown, повторный выпуск не запускается и ограничение фиксируется. Job done без нового served fingerprint считается провалом, старый leaf не удаляется ради прохождения теста.
|
||||||
|
|
||||||
|
Откат описан по exact IDs/fingerprints/files/record content и исходным settings/services/normalized export, контрольный CHR194 не меняется, перезагрузки/смена паролей не нужны. Публичная CA выдача не объявляется revoked. Справка native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates); факт замены проверяется измерением, документация его не подтверждает для текущего приложения.
|
||||||
|
|
||||||
|
Production код не менялся, Docker build/deploy не нужен, backend ux-certificates252/frontend ux-certificates251 сохранены. Следующий шаг — согласование конкретных двух выдач/renewal с включением www-ssl/api-ssl и полным откатом; разрешение250 относилось к уже завершённому выпуску. До согласия только подготовка/чтение. Реальное renewal, CA revoke и multi-instance остаются открыты.
|
||||||
|
|
||||||
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
||||||
|
|
||||||
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Тестовый сервер UX/UI — 2026-10-10
|
# Тестовый сервер UX/UI — 2026-10-10
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14: 252 — сертификаты используют strict-ID/enabled guards; renewal больше не объявляет failed/pending успешным и не подменяет неизвестный срок нулём. Восемь профильных scripts и 39 API/SQL checks прошли, own DB/role удалены. Backend ux-certificates252/frontend ux-certificates251 healthy, source526/dist1080 matched. Реальный Portal/read1440/390: оба CHR без ошибок, writes0. Следующий253 — подготовка реальной повторной выдачи/renewal и безопасного сравнения сертификата/TLS; эта приёмка ещё открыта. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14: 253 — подготовлена реальная приёмка renewal для exact mmt253-8e62a941.pngs.top на CHR104, read-only DNS empty/оба REST200. TLS/native SHA-256 comparator: positive и11 false-success отказов passed, syntax/lint passed. Никаких выдач/изменений253 не запускали. Runtime backend ux-certificates252/frontend ux-certificates251. Далее согласовать два выпуска/renewal с назначением SSL и полным откатом по deploy/TEST-ACME.md; этап12.5 открыт.
|
||||||
|
|
||||||
| Параметр | Проверенное состояние |
|
| Параметр | Проверенное состояние |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -34,6 +34,18 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro
|
|||||||
|
|
||||||
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
||||||
|
|
||||||
|
## 12.5.253 — подготовка проверки реальной замены сертификата при renewal (2026-10-14)
|
||||||
|
|
||||||
|
Подготовлен exact mmt253-8e62a941.pngs.top/certName mmt253-8e62a941 на CHR104/server2. Read-only preflight с Debian: точный FQDN и challenge name имеют0 Cloudflare records, оба CHR REST200 с прежними паролями. Ни DNS/settings/native writes, ни ACME orders не выполнялись. Это не свежий приватный baseline для будущей мутации: его нужно снять непосредственно перед запуском.
|
||||||
|
|
||||||
|
Новый ручной helper backend/scripts/acceptance/acme-renew-tls.mjs делает bounded15s TLS к фиксированному104:443 с exact SNI и rejectUnauthorized=true. Сверяет hostname, native SHA-256/private-key/name и served leaf. Compare требует изменения SHA-256 после повторного выпуска, совпадения native/TLS, корректных дат; output не перезаписывается. Ввод содержит только публичную native сводку, не keys/passwords. Один positive и11 negative comparator случаев passed без сети/CA; syntax и scoped ESLint passed. Это проверка проверяющего инструмента, не реального renewal. Native fingerprint другого алгоритма сначала пересчитывается из публичного PEM, не угадывается.
|
||||||
|
|
||||||
|
Процедура в [TEST-ACME](../deploy/TEST-ACME.md) включает свежий private baseline/settings/managed targets, единственный собственный target, первый UI выпуск, initial TLS, canonical date guard252 и один scheduler renewal. Code review пути settings выявил важное условие: PUT enabled=true вызывает refreshScheduler с немедленным запуском, поэтому дополнительный run-now запрещён. После terminal renewal выключается до следующего интервала. Если дата unknown, повторный выпуск не запускается и ограничение фиксируется. Job done без нового served fingerprint считается провалом, старый leaf не удаляется ради прохождения теста.
|
||||||
|
|
||||||
|
Откат описан по exact IDs/fingerprints/files/record content и исходным settings/services/normalized export, контрольный CHR194 не меняется, перезагрузки/смена паролей не нужны. Публичная CA выдача не объявляется revoked. Справка native полей/import: [MikroTik Certificates](https://help.mikrotik.com/docs/spaces/ROS/pages/2555969/Certificates); факт замены проверяется измерением, документация его не подтверждает для текущего приложения.
|
||||||
|
|
||||||
|
Production код не менялся, Docker build/deploy не нужен, backend ux-certificates252/frontend ux-certificates251 сохранены. Следующий шаг — согласование конкретных двух выдач/renewal с включением www-ssl/api-ssl и полным откатом; разрешение250 относилось к уже завершённому выпуску. До согласия только подготовка/чтение. Реальное renewal, CA revoke и multi-instance остаются открыты.
|
||||||
|
|
||||||
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
## 12.5.252 — выключенные серверы и достоверность результата renewal (2026-10-14)
|
||||||
|
|
||||||
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
Общий getter сертификатов теперь использует parseDbServerId и SQL enabled=true: numeric prefix/небезопасные ID не доходят до БД, выключенные серверы не возвращаются. Executor повторно отклоняет disabled перед DNS/native вызовами. Renewal использует каноническое наблюдаемое состояние вместо legacy expiry=0: неизвестный срок/статус пропускается, ошибка чтения/неоднозначное имя не запускает выпуск. После runner читается свежая запись задачи и проверяются id/server/name/source/domains/keyType/trustStore; renewed увеличивается только при status=done и step=done. Failed даёт error, queued/running и неподтверждённый результат не дают успеха. Local singleflight сохраняется; атомарная защита нескольких backend не заявляется.
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"date": "2026-10-14",
|
||||||
|
"block": "12.5.253",
|
||||||
|
"fqdn": "mmt253-8e62a941.pngs.top",
|
||||||
|
"serverId": "2",
|
||||||
|
"nativeTarget": "104.165.244.7",
|
||||||
|
"readOnlyPreflight": {
|
||||||
|
"exactDomainRecords": 0,
|
||||||
|
"challengeRecords": 0,
|
||||||
|
"chrRestStatus": [
|
||||||
|
200,
|
||||||
|
200
|
||||||
|
],
|
||||||
|
"writes": 0
|
||||||
|
},
|
||||||
|
"comparator": {
|
||||||
|
"positive": 1,
|
||||||
|
"negative": 11,
|
||||||
|
"passed": true,
|
||||||
|
"networkCalls": 0
|
||||||
|
},
|
||||||
|
"syntax": "passed",
|
||||||
|
"scopedLint": "passed",
|
||||||
|
"realRenewalExecuted": false,
|
||||||
|
"productionRuntimeChanged": false
|
||||||
|
}
|
||||||
Reference in new issue
Block a user