Обновлён дизайн внутренней лаборатории и добавлен поисковый экран по утверждённой системе «Түндүк».
Добавлены серверные учетные записи и cookie-сессии, создание первого admin, смена временного пароля, личный кабинет и управление учетными записями только для admin.
Поиск, документы, сохранение и экспорт оценок требуют авторизации; автор проверки берётся из сессии.
Добавлены инструкции по первому запуску, восстановлению пароля admin и настройке Secure cookie.
Проверки
python3 -m py_compile для изменённых Python-модулей.
node --check для встроенного JavaScript.
git diff --check.
Полные unit-тесты и визуальный просмотр в браузере не запускались в этой сессии.
Перед развертыванием настройте HTTPS reverse proxy и ограничение частоты запросов на вход.
## Что изменено
- Обновлён дизайн внутренней лаборатории и добавлен поисковый экран по утверждённой системе «Түндүк».
- Добавлены серверные учетные записи и cookie-сессии, создание первого `admin`, смена временного пароля, личный кабинет и управление учетными записями только для `admin`.
- Поиск, документы, сохранение и экспорт оценок требуют авторизации; автор проверки берётся из сессии.
- Добавлены инструкции по первому запуску, восстановлению пароля `admin` и настройке Secure cookie.
## Проверки
- `python3 -m py_compile` для изменённых Python-модулей.
- `node --check` для встроенного JavaScript.
- `git diff --check`.
- Полные unit-тесты и визуальный просмотр в браузере не запускались в этой сессии.
Перед развертыванием настройте HTTPS reverse proxy и ограничение частоты запросов на вход.
Review: блокирующих findings нет. Проверены auth/session, серверная проверка admin-доступа, cookie-флаги, хранение паролей/сессий, DB и связанный UI/deploy flow. Общая отображаемая роль соответствует требованию проекта. Полные тесты в этой сессии не запускались.
Review: блокирующих findings нет. Проверены auth/session, серверная проверка admin-доступа, cookie-флаги, хранение паролей/сессий, DB и связанный UI/deploy flow. Общая отображаемая роль соответствует требованию проекта. Полные тесты в этой сессии не запускались.
Повторный review актуального head 734631a: блокирующих findings нет. Проверил полный diff, включая changelog, и связанный auth/session, API, UI и production deploy flow. Неблокирующее замечание по покрытию: dedicated tests для новой auth/session/admin логики в PR отсутствуют; полный набор тестов в этой сессии не запускался.
Повторный review актуального head `734631a`: блокирующих findings нет. Проверил полный diff, включая changelog, и связанный auth/session, API, UI и production deploy flow. Неблокирующее замечание по покрытию: dedicated tests для новой auth/session/admin логики в PR отсутствуют; полный набор тестов в этой сессии не запускался.
Повторный review актуального head 075e58f: блокирующих findings нет. Проверил полный diff PR. SQLite миграция добавляет отсутствующие nullable INTEGER поля через PRAGMA table_info/ALTER TABLE, не пересоздаёт таблицы; входы и admin reset датируются в одной транзакции с выдачей сессии/сбросом. /auth/me возвращает только _public; timestamps доступны через /admin/users, защищённый admin-проверкой в handler и API. UI показывает эти поля только в списке пользователей. Полные тесты не запускались.
Повторный review актуального head `075e58f`: блокирующих findings нет. Проверил полный diff PR. SQLite миграция добавляет отсутствующие nullable INTEGER поля через `PRAGMA table_info`/`ALTER TABLE`, не пересоздаёт таблицы; входы и admin reset датируются в одной транзакции с выдачей сессии/сбросом. `/auth/me` возвращает только `_public`; timestamps доступны через `/admin/users`, защищённый admin-проверкой в handler и API. UI показывает эти поля только в списке пользователей. Полные тесты не запускались.
[P1] Обязательную смену временного пароля можно обойти (backend/search/api.py:322, backend/search/auth.py:132-135). /auth/change-password передаёт отсутствующее current_password как None, а AuthStore.change_password в этом случае вообще не сверяет старый пароль и не проверяет, что новый отличается от старого. Воспроизведение на текущем head: создать пользователя с временным паролем, войти и отправить POST /auth/change-password только с new_password, равным временному. Ответ — 200, must_change_password становится false, прежний пароль продолжает работать. Таким же запросом любой обладатель действующей сессии может сменить пароль без знания текущего. Требуйте текущий пароль в пользовательском маршруте и отклоняйте повторное использование временного пароля.
Проверка: 35 backend unit-тестов прошли (1 skipped); новый сценарий воспроизведён отдельно. Тестов для auth/session в PR нет.
[P1] Обязательную смену временного пароля можно обойти (`backend/search/api.py:322`, `backend/search/auth.py:132-135`). `/auth/change-password` передаёт отсутствующее `current_password` как `None`, а `AuthStore.change_password` в этом случае вообще не сверяет старый пароль и не проверяет, что новый отличается от старого. Воспроизведение на текущем head: создать пользователя с временным паролем, войти и отправить `POST /auth/change-password` только с `new_password`, равным временному. Ответ — 200, `must_change_password` становится false, прежний пароль продолжает работать. Таким же запросом любой обладатель действующей сессии может сменить пароль без знания текущего. Требуйте текущий пароль в пользовательском маршруте и отклоняйте повторное использование временного пароля.
Проверка: 35 backend unit-тестов прошли (1 skipped); новый сценарий воспроизведён отдельно. Тестов для auth/session в PR нет.
Review актуального head 7912fdd: блокирующих findings нет. Пропуск/нестроковый current_password отклоняется; повтор старого пароля сравнивается с прежним salt/hash и отклоняется. Forced flow остаётся рабочим: логин выдаёт сессию для смены, проверяется временный пароль, затем новый отличный пароль сохраняется и сессия выдаётся заново. Reset отзывает старые сессии; timestamps доступны только через admin-protected /admin/users, не через /auth/me. Полный diff и связанные auth/UI/SQLite пути просмотрены; тесты не запускал.
Review актуального head `7912fdd`: блокирующих findings нет. Пропуск/нестроковый `current_password` отклоняется; повтор старого пароля сравнивается с прежним salt/hash и отклоняется. Forced flow остаётся рабочим: логин выдаёт сессию для смены, проверяется временный пароль, затем новый отличный пароль сохраняется и сессия выдаётся заново. Reset отзывает старые сессии; timestamps доступны только через admin-protected `/admin/users`, не через `/auth/me`. Полный diff и связанные auth/UI/SQLite пути просмотрены; тесты не запускал.
Финальный review актуального head 6de2f47: блокирующих findings нет. Запись CHANGELOG для 0.11.2 соответствует фиксу смены пароля и включает первый вход с временным паролем. Полный diff PR и связанные auth/session, SQLite migration, admin ACL, timestamps и UI повторно учтены; проверки предыдущего review остаются в силе. git diff --check чистый; полные тесты не запускались.
Финальный review актуального head `6de2f47`: блокирующих findings нет. Запись CHANGELOG для `0.11.2` соответствует фиксу смены пароля и включает первый вход с временным паролем. Полный diff PR и связанные auth/session, SQLite migration, admin ACL, timestamps и UI повторно учтены; проверки предыдущего review остаются в силе. `git diff --check` чистый; полные тесты не запускались.
Исправление замечания по /auth/change-password проверено на коммите 6de2f47: запрос без текущего пароля, с неверным паролем и с тем же временным паролем возвращает 400; корректная смена возвращает 200, прежний пароль и сессия больше не действуют. 35 backend-тестов прошли (1 skipped). Новых блокирующих замечаний нет.
Исправление замечания по `/auth/change-password` проверено на коммите `6de2f47`: запрос без текущего пароля, с неверным паролем и с тем же временным паролем возвращает 400; корректная смена возвращает 200, прежний пароль и сессия больше не действуют. 35 backend-тестов прошли (1 skipped). Новых блокирующих замечаний нет.
admin
merged commit 88fd84a515 into main2026-10-10 18:30:31 +00:00
Повторная проверка UI-исправлений на коммите 6702f01 (исходная ветка после слияния PR).
[P2] На ширине окна 801–969 px экран поиска остаётся трёхколоночным: backend/search/review.html:100 задаёт минимальные ширины 230 + 320 + 420 = 970 px, а переход к одной колонке в строках 122–126 срабатывает только при max-width: 800px. Поэтому на планшетной ширине содержимое выходит за пределы окна и появляется горизонтальная прокрутка. Перенесите переключение сетки на ширину не ниже 970 px либо уменьшите минимумы колонок.
Новые правки модального фокуса и переноса навигации просмотрены; node --check встроенного JS и 35 backend-тестов прошли (1 skipped). Браузерный визуальный прогон в этом окружении недоступен. Важно: PR уже слит в main на 88fd84a, а 6702f01 пока есть только в исходной ветке — UI-исправления не входят в текущий main.
Повторная проверка UI-исправлений на коммите `6702f01` (исходная ветка после слияния PR).
[P2] На ширине окна 801–969 px экран поиска остаётся трёхколоночным: `backend/search/review.html:100` задаёт минимальные ширины 230 + 320 + 420 = 970 px, а переход к одной колонке в строках 122–126 срабатывает только при `max-width: 800px`. Поэтому на планшетной ширине содержимое выходит за пределы окна и появляется горизонтальная прокрутка. Перенесите переключение сетки на ширину не ниже 970 px либо уменьшите минимумы колонок.
Новые правки модального фокуса и переноса навигации просмотрены; `node --check` встроенного JS и 35 backend-тестов прошли (1 skipped). Браузерный визуальный прогон в этом окружении недоступен. Важно: PR уже слит в `main` на `88fd84a`, а `6702f01` пока есть только в исходной ветке — UI-исправления не входят в текущий `main`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Что изменено
admin, смена временного пароля, личный кабинет и управление учетными записями только дляadmin.adminи настройке Secure cookie.Проверки
python3 -m py_compileдля изменённых Python-модулей.node --checkдля встроенного JavaScript.git diff --check.Перед развертыванием настройте HTTPS reverse proxy и ограничение частоты запросов на вход.
Review: блокирующих findings нет. Проверены auth/session, серверная проверка admin-доступа, cookie-флаги, хранение паролей/сессий, DB и связанный UI/deploy flow. Общая отображаемая роль соответствует требованию проекта. Полные тесты в этой сессии не запускались.
Повторный review актуального head
734631a: блокирующих findings нет. Проверил полный diff, включая changelog, и связанный auth/session, API, UI и production deploy flow. Неблокирующее замечание по покрытию: dedicated tests для новой auth/session/admin логики в PR отсутствуют; полный набор тестов в этой сессии не запускался.Повторный review актуального head
075e58f: блокирующих findings нет. Проверил полный diff PR. SQLite миграция добавляет отсутствующие nullable INTEGER поля черезPRAGMA table_info/ALTER TABLE, не пересоздаёт таблицы; входы и admin reset датируются в одной транзакции с выдачей сессии/сбросом./auth/meвозвращает только_public; timestamps доступны через/admin/users, защищённый admin-проверкой в handler и API. UI показывает эти поля только в списке пользователей. Полные тесты не запускались.[P1] Обязательную смену временного пароля можно обойти (
backend/search/api.py:322,backend/search/auth.py:132-135)./auth/change-passwordпередаёт отсутствующееcurrent_passwordкакNone, аAuthStore.change_passwordв этом случае вообще не сверяет старый пароль и не проверяет, что новый отличается от старого. Воспроизведение на текущем head: создать пользователя с временным паролем, войти и отправитьPOST /auth/change-passwordтолько сnew_password, равным временному. Ответ — 200,must_change_passwordстановится false, прежний пароль продолжает работать. Таким же запросом любой обладатель действующей сессии может сменить пароль без знания текущего. Требуйте текущий пароль в пользовательском маршруте и отклоняйте повторное использование временного пароля.Проверка: 35 backend unit-тестов прошли (1 skipped); новый сценарий воспроизведён отдельно. Тестов для auth/session в PR нет.
Review актуального head
7912fdd: блокирующих findings нет. Пропуск/нестроковыйcurrent_passwordотклоняется; повтор старого пароля сравнивается с прежним salt/hash и отклоняется. Forced flow остаётся рабочим: логин выдаёт сессию для смены, проверяется временный пароль, затем новый отличный пароль сохраняется и сессия выдаётся заново. Reset отзывает старые сессии; timestamps доступны только через admin-protected/admin/users, не через/auth/me. Полный diff и связанные auth/UI/SQLite пути просмотрены; тесты не запускал.Финальный review актуального head
6de2f47: блокирующих findings нет. Запись CHANGELOG для0.11.2соответствует фиксу смены пароля и включает первый вход с временным паролем. Полный diff PR и связанные auth/session, SQLite migration, admin ACL, timestamps и UI повторно учтены; проверки предыдущего review остаются в силе.git diff --checkчистый; полные тесты не запускались.Исправление замечания по
/auth/change-passwordпроверено на коммите6de2f47: запрос без текущего пароля, с неверным паролем и с тем же временным паролем возвращает 400; корректная смена возвращает 200, прежний пароль и сессия больше не действуют. 35 backend-тестов прошли (1 skipped). Новых блокирующих замечаний нет.Повторная проверка UI-исправлений на коммите
6702f01(исходная ветка после слияния PR).[P2] На ширине окна 801–969 px экран поиска остаётся трёхколоночным:
backend/search/review.html:100задаёт минимальные ширины 230 + 320 + 420 = 970 px, а переход к одной колонке в строках 122–126 срабатывает только приmax-width: 800px. Поэтому на планшетной ширине содержимое выходит за пределы окна и появляется горизонтальная прокрутка. Перенесите переключение сетки на ширину не ниже 970 px либо уменьшите минимумы колонок.Новые правки модального фокуса и переноса навигации просмотрены;
node --checkвстроенного JS и 35 backend-тестов прошли (1 skipped). Браузерный визуальный прогон в этом окружении недоступен. Важно: PR уже слит вmainна88fd84a, а6702f01пока есть только в исходной ветке — UI-исправления не входят в текущийmain.