Сверка

Проверка доступности литературы пяти образовательных программ НИУ ВШЭ. Целевой адрес: https://miem.space/courses. Авторизация не требуется.

Запуск

Требуется Node.js24 и pnpm11.25.0.

pnpm install --frozen-lockfile
TEST_DATABASE_URL=<изолированная-локальная-БД-sverka_test> pnpm test
pnpm typecheck
pnpm dev

Открыть http://127.0.0.1:5173/courses. Для сервера требуется DATABASE_URL с подключением к отдельной базе PostgreSQL. Там хранятся результаты, очередь и расписание; новое пустое хранилище инициализируется при первом подключении. Пароль передаётся только через окружение или защищённый файл окружения вне Git. COURSES_ORIGIN задаёт допустимый Origin для POST за reverse proxy, в production — https://miem.space.

Ручная проверка выполняется порциями, пока вкладка открыта. После её закрытия или перезапуска сервера кнопка «Продолжить» использует сохранённую очередь. Глобальная аренда не допускает одновременную обработку одной порции. Каждая порция сохраняет результаты и очередь в одной транзакции PostgreSQL; при ошибке записи задания остаются в очереди.

Страницы курсов сравниваются по контрольной сумме. Неизменившийся список литературы переиспользуется, но доступность внешних ссылок проверяется отдельно: кэш сутки для подтверждённых ограничений, десять минут для неопределённых результатов и временных ошибок. Версия правил входит в проверку свежести; старые HTTP-only результаты показываются как устаревшие и при следующем запуске пересчитываются. Полная проверка игнорирует кэш. Литература только во вложении отмечается как неполный охват.

Доступ к полному тексту

Требование авторизации, подписки или покупки онлайн-доступа означает недоступность книги. Аннотация, оглавление и ознакомительный фрагмент не подтверждают доступ к полному тексту. HTTP200 и Content-Type PDF сами по себе не дают зелёный статус; при недостатке доказательств возвращается unknown. Даже полученный PDF может быть фрагментом издания.

Правила учитывают сообщения читалок Лани, Юрайта и iBooks, изъятие публикации и предложение покупки онлайн-доступа Znanium, покупку именно eBook Springer и гостевое ограничение BOOK.ru. Цена печатной книги и общий запрет скачивания PDF не доказывают закрытое чтение. Результат содержит короткое доказательство, URL без токенов, время, версию правил и профиль anonymous.

Страницы известных ЭБС открываются в Chromium/Playwright для подтверждения видимых ограничений: скрытые CSS-шаблоны не считаются доказательством; проверяется видимый текст, при необходимости адрес читалки, а у BOOK.ru — подсказка к гостевому просмотру. Для остальных сайтов неопределённость сохраняется. Проверка не выполняет вход, покупку и обход CAPTCHA.

Docker включает Chromium с включённой песочницей, UID1000, read-only rootfs, no-new-privileges и cap-drop ALL. Профиль seccomp разрешает необходимые для песочницы user namespaces, остальные ограничения остаются; источник и лицензия указаны в deploy/README.md. Браузер получает минимальное окружение без DATABASE_URL. Все HTTP-запросы перехватываются, DNS проверяется и закрепляется в Node-сокете. Прямой выход блокируется нерабочим proxy, WebSocket/SW отключены, непроходящий через proxy WebRTC UDP запрещён. Методы записи, внешние домены, изображения/медиа/шрифты блокируются. Лимиты:100 запросов,32MB на задачу,8MB на ресурс,10 одновременных запросов; browser deadline30s и общий link deadline60s. Ошибка/лимит оставляет доступ неподтверждённым.

Локальная разработка браузерной части рекомендована в Docker с тем же seccomp-профилем. pnpm test:browser с локальной изолированной TEST_DATABASE_URL проверяет реальный Chromium и запрет обращений к локальному HTTP/UDP серверу через fetch, redirect, iframe, popup, worker, WebSocket и WebRTC. Обычные pnpm test также проверяют DNS/IP pinning и правила провайдеров.

Частота запросов

Материалы проверяются последовательно. Между запросами к одному хосту выдерживается 2 секунды, включая каталоги, курсы и перенаправления. В браузерной проверке пауза применяется к навигациям; JS/CSS и anonymous API загружаются с ограничением параллелизма, без двухсекундной паузы на каждый ресурс. Ограничение общее для API и worker и сохраняется в PostgreSQL. После HTTP429/503 действует пауза из Retry-After (не менее минуты), после HTTP403 — пять минут. Повторных попыток в цикле нет. Ссылки, пропущенные во время паузы, отмечаются как ограниченные с датой окончания паузы; это не подтверждает, что материал удалён. Их можно обновить последующей полной проверкой. Статическая загрузка ограничена30 секундами, вся проверка ссылки с браузером —60 секундами. Proxy read timeout85s оставляет время на сохранение результата в пределах90s lease. Паузы снижают нагрузку, но не гарантируют отсутствие блокировки со стороны сайта.

Расписание

В интерфейсе откройте «Проверка по расписанию»: включите автоматический запуск, выберите ежедневное или еженедельное повторение, время по Москве, при необходимости день недели и режим кэша. Сохранение и отключение доступны там же. По умолчанию расписание выключено; оно общее для всех посетителей и хранится в той же базе PostgreSQL.

pnpm dev, pnpm start и Docker запускают веб-сервер и отдельный фоновый процесс одним управляемым runtime. Проверка по расписанию выполняется без открытой вкладки, при перезапуске продолжается по сохранённой очереди. Расписание проверяется раз в пять секунд. Ручные проверки сохраняют прежний режим с открытой вкладкой.

Если любая предыдущая проверка ещё имеет статус running, совпавший слот пропускается с отметкой в интерфейсе: параллельных запусков нет. После простоя сервера выполняется один просроченный запуск; пропущенные дни не образуют очередь. Изменение или отключение расписания не прерывает уже начатую автоматическую проверку. Если один из двух процессов runtime завершится, второй останавливается; restart policy Docker поднимает их вместе.

Production

docker compose build
docker compose up -d

Эти команды изменяют production: выполнять только через разрешённый deployment-процесс после независимого review. Сервис слушает только 127.0.0.1:3011, работает от UID1000 и использует существующий сервер PostgreSQL через внешнюю Docker-сеть miem_workers_default. Отдельный контейнер БД или SQLite volume не создаётся. Healthcheck: GET /courses/api/health. Порт3011 — предлагаемый; перед запуском проверить, что он свободен. Код не зависит от Cloudflare Workers, D1 или Sites hosting.

Добавить deploy/nginx-courses.conf в существующий TLS-server miem.space, проверить nginx -t, затем выполнить разрешённый reload. Конфиг передаёт исходный URI без удаления /courses; /courses-other не захватывается. Фактический путь Nginx-конфига должен быть подтверждён read-only preflight, а не угадан.

Порядок первого deployment

  1. Подтвердить актуальные branch/head, независимое review, тесты, сборку, Docker daemon/диск, свободный порт и отсутствие существующей локации /courses.
  2. Сохранить текущую конфигурацию Nginx. Использовать отдельную базу miem_courses_links и отдельную LOGIN-роль без SUPERUSER/CREATEDB/CREATEROLE. Не использовать учётную запись и таблицы существующих приложений. Перед изменением уже заполненной базы сделать pg_dump и проверить возможность восстановления; на первом размещении новая база пустая.
  3. Собрать exact commit, запустить только новый сервис. Проверить localhost healthcheck и /courses, статические файлы и шрифты.
  4. Включить Nginx location, выполнить syntax check/reload через разрешённый канал. Проверить HTTPS страницу, healthcheck и ручной шаг проверки, затем перезапуск сервиса с сохранением данных.
  5. При неудаче вернуть прежний Nginx-конфиг, проверить и reload; остановить только новый сервис. Базу и роль не удалять. При обновлении вернуть предыдущий совместимый image tag, сохранив PostgreSQL. Не применять compose down -v или общий prune.

Обновление Nginx обычно не требует остановки существующих сервисов; фактический риск и разрешённый способ reload определяются инфраструктурным runbook. DATABASE_URL передаётся Docker Compose из окружения либо через защищённый deployment env-file; его содержимое не публикуется и не коммитится. В этом checkout production deployment не выполнен.

Проверки

TEST_DATABASE_URL должен вести только на локальный sverka_test; DB-тесты создают и удаляют собственные случайные схемы и отказываются работать с другой базой. pnpm test проверяет извлечение ссылок, классификацию, URL со скобками, запрет непубличных IP, атомарный rollback/replay очереди, единственный общий запуск, lease, создание/изменение/отключение расписания, московское время и переходы календаря, однократный claim, skip пересекающихся запусков и выполнение worker без браузера. Node HTTP-загрузчик закрепляет проверенный DNS-адрес в сокете и проверяет каждый redirect; TLS проверяет исходное имя хоста. Прокси из environment не используются загрузчиком.

S
Description
No description provided
Readme
568 KiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 96.6%
Dockerfile 1.4%
JavaScript 1.2%
CSS 0.8%