Подготовить воспроизводимую инфраструктуру production VPS #42

Merged
admin merged 17 commits from feature/infrastructure-documentation-and-bootstrap into main 2026-10-11 20:22:23 +00:00
Collaborator

Что изменено

  • Добавлены root-only bootstrap и read-only drift verifier, inventory и операционные документы.
  • Добавлены Caddy HTTPS proxy, приватные Compose-сети и Docker secret для review signing key.
  • Добавлен холодный backup с проверкой остановленных сервисов, SQLite integrity, SHA-256, Git revision, deployment hashes и image IDs.
  • Добавлено применение staged restore только на помеченном recovery-хосте; оно сверяет identity хоста, чистый Git revision, пустые пути/volumes, права секретов и оставляет сервисы остановленными.
  • Добавлены root-owned read-only verifier и guarded rollback helper с точными sudoers-командами; общего sudo и доступа к Docker codex не получает.
  • Gitea Actions проверяет Python suites, shell syntax, host guards, rollback helper, Compose/Caddyfile и собирает production images. Публикация и deploy выключены.
  • ACCESS и CURRENT_STATE отражают WSL2 и проверки VPS из текущего сеанса.

Проверки

  • Backend: 37 passed, 1 OpenSearch integration skipped без AKYLDASH_OPENSEARCH_URL.
  • Telegram: 6 passed; backup/restore: 9 passed; rollback: 3 passed.
  • Host identity guard, verifier argument guard, Bash/Python syntax, CI YAML и git diff checks прошли.
  • Локальный изолированный Compose smoke test: OpenSearch, backend, Caddy healthy; GET /review через Caddy вернул HTTP 200. Временные containers, networks и volumes удалены.
  • Production Caddyfile прошёл caddy validate.

Ограничения

Read-only SSH подтвердил, что на VPS у codex нет sudo, Docker и Git. Production bootstrap, установка helpers, backup/restore на реальных данных и публичный TLS не проверялись. Gitea CI для текущего head 9084fd4 всё ещё Waiting to run; runner availability API требует владельца репозитория (403). Требуется ручное ревью; PR не объединён.

## Что изменено - Добавлены root-only bootstrap и read-only drift verifier, inventory и операционные документы. - Добавлены Caddy HTTPS proxy, приватные Compose-сети и Docker secret для review signing key. - Добавлен холодный backup с проверкой остановленных сервисов, SQLite integrity, SHA-256, Git revision, deployment hashes и image IDs. - Добавлено применение staged restore только на помеченном recovery-хосте; оно сверяет identity хоста, чистый Git revision, пустые пути/volumes, права секретов и оставляет сервисы остановленными. - Добавлены root-owned read-only verifier и guarded rollback helper с точными sudoers-командами; общего sudo и доступа к Docker codex не получает. - Gitea Actions проверяет Python suites, shell syntax, host guards, rollback helper, Compose/Caddyfile и собирает production images. Публикация и deploy выключены. - ACCESS и CURRENT_STATE отражают WSL2 и проверки VPS из текущего сеанса. ## Проверки - Backend: 37 passed, 1 OpenSearch integration skipped без AKYLDASH_OPENSEARCH_URL. - Telegram: 6 passed; backup/restore: 9 passed; rollback: 3 passed. - Host identity guard, verifier argument guard, Bash/Python syntax, CI YAML и git diff checks прошли. - Локальный изолированный Compose smoke test: OpenSearch, backend, Caddy healthy; GET /review через Caddy вернул HTTP 200. Временные containers, networks и volumes удалены. - Production Caddyfile прошёл caddy validate. ## Ограничения Read-only SSH подтвердил, что на VPS у codex нет sudo, Docker и Git. Production bootstrap, установка helpers, backup/restore на реальных данных и публичный TLS не проверялись. Gitea CI для текущего head 9084fd4 всё ещё Waiting to run; runner availability API требует владельца репозитория (403). Требуется ручное ревью; PR не объединён.
codex added 1 commit 2026-10-11 15:27:53 +00:00
codex added 1 commit 2026-10-11 15:32:21 +00:00
Усилить read-only drift-проверку VPS
CI / tests-and-images (pull_request) Has been cancelled
5c78f7ebb8
codex added 1 commit 2026-10-11 15:35:12 +00:00
codex added 1 commit 2026-10-11 15:36:45 +00:00
Закрепить версию Python в CI
CI / tests-and-images (pull_request) Has been cancelled
892781522d
codex added 1 commit 2026-10-11 15:37:32 +00:00
codex added 1 commit 2026-10-11 15:42:19 +00:00
codex added 1 commit 2026-10-11 15:57:23 +00:00
Configure Caddy HTTPS proxy for production
CI / tests-and-images (pull_request) Has been cancelled
fb556228c7
codex added 1 commit 2026-10-11 16:12:16 +00:00
Add cold backup and staged restore tooling
CI / tests-and-images (pull_request) Has been cancelled
97803ca5de
codex added 1 commit 2026-10-11 16:17:02 +00:00
Guard recovery bootstrap from production host
CI / tests-and-images (pull_request) Has been cancelled
16f97d5f73
codex added 1 commit 2026-10-11 16:31:07 +00:00
Add guarded rollback and recovery apply tools
CI / tests-and-images (pull_request) Has been cancelled
6f809d3196
codex added 1 commit 2026-10-11 16:35:23 +00:00
Document WSL access and verify VPS state
CI / tests-and-images (pull_request) Has been cancelled
711700fcc9
codex added 1 commit 2026-10-11 16:39:16 +00:00
Expose drift verifier through a fixed sudo helper
CI / tests-and-images (pull_request) Has been cancelled
02cf4e6e95
codex added 1 commit 2026-10-11 16:41:05 +00:00
Test restricted verifier argument guard
CI / tests-and-images (pull_request) Has been cancelled
9084fd4f16
agent requested changes 2026-10-11 19:45:56 +00:00
Dismissed
agent left a comment
Collaborator

Проверил PR независимо. Нужны исправления в процедурах первого развёртывания: сейчас описанный порядок нельзя выполнить с добавленным архиватором, а README production противоречит новой схеме доступа и резервного копирования. Локально прошли backend (37, 1 skip), Telegram (6), backup/restore (9), rollback (3), оба shell guard теста. На production запуск и восстановление не проверялись.

Проверил PR независимо. Нужны исправления в процедурах первого развёртывания: сейчас описанный порядок нельзя выполнить с добавленным архиватором, а README production противоречит новой схеме доступа и резервного копирования. Локально прошли backend (37, 1 skip), Telegram (6), backup/restore (9), rollback (3), оба shell guard теста. На production запуск и восстановление не проверялись.
@@ -19,0 +27,4 @@
the existing firewall rules and allow TCP `80` and `443` before Caddy starts.
Caddy requests and renews the origin certificate automatically; use
Cloudflare Full (strict) only after HTTPS succeeds.
5. Complete and verify the backup/restore setup before starting production.
Collaborator

P2 — инструкция production устарела и противоречит этой же ветке. Здесь сказано, что проверенного backup-скрипта нет, хотя PR добавляет infra/backup/archive.py и процедуру в docs/operations/BACKUP.md. Шаги ниже запускают docker compose без sudo и используют .env в checkout, тогда как новая схема требует root-действий, не даёт codex доступ к Docker и хранит env в /etc/akyldash/production.env. Обновите README до одного выполнимого порядка для владельца VPS.

**P2 — инструкция production устарела и противоречит этой же ветке.** Здесь сказано, что проверенного backup-скрипта нет, хотя PR добавляет `infra/backup/archive.py` и процедуру в `docs/operations/BACKUP.md`. Шаги ниже запускают `docker compose` без `sudo` и используют `.env` в checkout, тогда как новая схема требует root-действий, не даёт `codex` доступ к Docker и хранит env в `/etc/akyldash/production.env`. Обновите README до одного выполнимого порядка для владельца VPS.
@@ -0,0 +31,4 @@
existing SSH access. The Compose Caddy service obtains and renews its HTTPS
certificate automatically; Cloudflare Full (strict) still needs owner-side
verification.
5. Create and verify the first backup before starting services. Load and
Collaborator

P1 — первый backup по этой инструкции невозможен. infra/backup/archive.py:138–163 требует, чтобы у всех сервисов уже существовали остановленные Compose-контейнеры. На чистом VPS до первого up/create их нет, поэтому create завершается ошибкой Compose has no containers. Кроме того, backup до загрузки индекса и создания admin не покрывает эти данные. Добавьте выполнимый порядок для первоначального создания контейнеров/томов и отдельный проверенный backup после инициализации данных.

**P1 — первый backup по этой инструкции невозможен.** `infra/backup/archive.py:138–163` требует, чтобы у всех сервисов уже существовали остановленные Compose-контейнеры. На чистом VPS до первого `up`/`create` их нет, поэтому `create` завершается ошибкой `Compose has no containers`. Кроме того, backup до загрузки индекса и создания admin не покрывает эти данные. Добавьте выполнимый порядок для первоначального создания контейнеров/томов и отдельный проверенный backup после инициализации данных.
codex added 1 commit 2026-10-11 19:50:47 +00:00
Fix production backup bootstrap guidance
CI / tests-and-images (pull_request) Has been cancelled
d6d029d98c
codex added 1 commit 2026-10-11 19:51:50 +00:00
Verify offline data backup without containers
CI / tests-and-images (pull_request) Has been cancelled
f6c9b9883a
agent requested changes 2026-10-11 19:56:01 +00:00
Dismissed
agent left a comment
Collaborator

Повторно проверил исправления на текущем head. Замечание про устаревший production README исправлено, новый архиватор корректно различает пустое хранилище и отсутствие контейнеров в покрытых тестами случаях. Первый запуск с предусмотренным инструкцией заранее загруженным корпусом всё ещё не имеет выполнимого безопасного порядка, поэтому оставляю Request changes. Локально прошли backend (37, 1 skip), Telegram (6), backup/restore (15), rollback (3), shell guard тесты и git diff --check.

Повторно проверил исправления на текущем head. Замечание про устаревший production README исправлено, новый архиватор корректно различает пустое хранилище и отсутствие контейнеров в покрытых тестами случаях. Первый запуск с предусмотренным инструкцией заранее загруженным корпусом всё ещё не имеет выполнимого безопасного порядка, поэтому оставляю Request changes. Локально прошли backend (37, 1 skip), Telegram (6), backup/restore (15), rollback (3), shell guard тесты и `git diff --check`.
@@ -59,0 +40,4 @@
On a clean first deployment, `infra/backup/archive.py create` reports that no
backup is required when all persistent mounts are empty and no Compose
containers exist. Continue without a backup in that case. If any persistent
data exists, create and verify a backup before changing schema, images, or
Collaborator

P1 — первый запуск с заранее загруженным корпусом по этой процедуре блокируется. Строки 24–25 требуют положить minjust-normalized в DATA_ROOT до запуска. На новом VPS именованные тома Compose ещё не созданы; compose_sources() видит непустой bind mount и отсутствующие тома и выдаёт persistent Compose volumes are missing while data exists (infra/backup/archive.py:187–192). Это прямо зафиксировано новым тестом test_existing_data_with_missing_named_volume_is_rejected_as_incomplete. Предложенное здесь create and verify a backup выполнить невозможно, а пропускать backup при существующем корпусе инструкция запрещает. Нужен описанный и проверенный путь первоначального создания пустых томов и backup корпуса до up либо другой безопасный порядок.

**P1 — первый запуск с заранее загруженным корпусом по этой процедуре блокируется.** Строки 24–25 требуют положить `minjust-normalized` в `DATA_ROOT` до запуска. На новом VPS именованные тома Compose ещё не созданы; `compose_sources()` видит непустой bind mount и отсутствующие тома и выдаёт `persistent Compose volumes are missing while data exists` (`infra/backup/archive.py:187–192`). Это прямо зафиксировано новым тестом `test_existing_data_with_missing_named_volume_is_rejected_as_incomplete`. Предложенное здесь `create and verify a backup` выполнить невозможно, а пропускать backup при существующем корпусе инструкция запрещает. Нужен описанный и проверенный путь первоначального создания пустых томов и backup корпуса до `up` либо другой безопасный порядок.
@@ -0,0 +37,4 @@
are no containers and all persistent mounts are empty. If any data exists,
create and verify a backup before starting a new version. An uncertain or
partial state stops deployment. Then start services, load and validate the
OpenSearch index, create the initial admin interactively, and verify
Collaborator

P2 — после инициализации данных процедура оставляет первый релиз без восстановимой точки. Для действительно пустого хоста backup пропускается, затем создаются индекс и admin, но шаги не останавливают сервисы и не создают проверенный backup новых SQLite/OpenSearch данных перед завершением первого развёртывания. Добавьте обязательный холодный backup и проверку restore после этой инициализации, прежде чем считать production готовым.

**P2 — после инициализации данных процедура оставляет первый релиз без восстановимой точки.** Для действительно пустого хоста backup пропускается, затем создаются индекс и admin, но шаги не останавливают сервисы и не создают проверенный backup новых SQLite/OpenSearch данных перед завершением первого развёртывания. Добавьте обязательный холодный backup и проверку restore после этой инициализации, прежде чем считать production готовым.
codex added 1 commit 2026-10-11 19:59:30 +00:00
Back up preloaded corpus before first deployment
CI / tests-and-images (pull_request) Has been cancelled
752266d408
agent requested changes 2026-10-11 20:14:50 +00:00
Dismissed
agent left a comment
Collaborator

Проверил коммит 752266d. Ранее отмеченный случай с заранее загруженным корпусом теперь обрабатывается и покрыт тестом. Однако допуск отсутствующих томов создаёт риск неполного backup уже работавшей установки, а обязательный backup после первой инициализации индекса и admin всё ещё не добавлен. Поэтому оставляю Request changes. Локальные suites прошли: backend 37 (1 skip), Telegram 6, backup/restore 15, rollback 3; shell guards и git diff --check прошли.

Проверил коммит 752266d. Ранее отмеченный случай с заранее загруженным корпусом теперь обрабатывается и покрыт тестом. Однако допуск отсутствующих томов создаёт риск неполного backup уже работавшей установки, а обязательный backup после первой инициализации индекса и admin всё ещё не добавлен. Поэтому оставляю Request changes. Локальные suites прошли: backend 37 (1 skip), Telegram 6, backup/restore 15, rollback 3; shell guards и `git diff --check` прошли.
@@ -63,0 +69,4 @@
sudo docker compose --env-file /etc/akyldash/production.env -f deploy/production/compose.yaml exec backend python -m search.api --create-admin
```
The account database is `$DATA_ROOT/search-users.sqlite3` and is included in
Collaborator

P2 — нет обязательного backup после первой инициализации. Порядок для полностью пустого хоста пропускает backup, затем создаёт индекс и admin, но не требует остановить сервисы, сделать и проверить архив получившихся SQLite/OpenSearch данных и пробное staged restore. В docs/operations/DEPLOYMENT.md последовательность заканчивается проверкой /review и записью image ID. Добавьте эту процедуру до признания первого развёртывания завершённым.

**P2 — нет обязательного backup после первой инициализации.** Порядок для полностью пустого хоста пропускает backup, затем создаёт индекс и admin, но не требует остановить сервисы, сделать и проверить архив получившихся SQLite/OpenSearch данных и пробное staged restore. В `docs/operations/DEPLOYMENT.md` последовательность заканчивается проверкой `/review` и записью image ID. Добавьте эту процедуру до признания первого развёртывания завершённым.
@@ -0,0 +188,4 @@
persistent_data = has_persistent_data(storage)
if not containers and not persistent_data:
raise ValueError("no backup is required for a clean first deployment; skip backup and start the initial stack")
if containers and any(path is None for path in storage.values()):
Collaborator

P1 — отсутствующий том после прежнего запуска теперь молча попадает в «проверенный» backup как пустой. Условие допускает None для любого named volume всякий раз, когда контейнеров нет, без признака именно первого развёртывания. Например, после docker compose down и потери akyldash_opensearch-data оставшиеся SQLite/корпус в DATA_ROOT делают persistent_data=True; код создаст архив с пустым opensearch/ и успешной SHA-проверкой вместо отказа из-за утраченного индекса. Новый тест подтверждает такое поведение для существующих данных и отсутствующего тома. Разрешайте пустые компоненты только при явно проверенном первом запуске; в остальных случаях прекращайте backup как неполный.

**P1 — отсутствующий том после прежнего запуска теперь молча попадает в «проверенный» backup как пустой.** Условие допускает `None` для любого named volume всякий раз, когда контейнеров нет, без признака именно первого развёртывания. Например, после `docker compose down` и потери `akyldash_opensearch-data` оставшиеся SQLite/корпус в `DATA_ROOT` делают `persistent_data=True`; код создаст архив с пустым `opensearch/` и успешной SHA-проверкой вместо отказа из-за утраченного индекса. Новый тест подтверждает такое поведение для существующих данных и отсутствующего тома. Разрешайте пустые компоненты только при явно проверенном первом запуске; в остальных случаях прекращайте backup как неполный.
codex added 1 commit 2026-10-11 20:17:56 +00:00
Guard volume gaps and back up initialized production
CI / tests-and-images (pull_request) Has been cancelled
3b41d1f20f
agent approved these changes 2026-10-11 20:21:36 +00:00
agent left a comment
Collaborator

Повторно проверил исправления на head 3b41d1f. Оба прежних замечания устранены: отсутствие именованных томов допускается только при явном --initial-deployment и корпусе как единственном содержимом DATA_ROOT; обычный backup отказывает при пропавших томах. В инструкции добавлен обязательный проверенный backup после загрузки индекса и создания admin. Локально прошли backend (37, 1 skip), Telegram (6), backup/restore (16), rollback (3), shell guards, git diff --check; отдельно проверил создание, проверку и staging-restore архива корпуса с отсутствующими томами. Production VPS и публичный TLS в рамках ревью не проверялись.

Повторно проверил исправления на head 3b41d1f. Оба прежних замечания устранены: отсутствие именованных томов допускается только при явном `--initial-deployment` и корпусе как единственном содержимом DATA_ROOT; обычный backup отказывает при пропавших томах. В инструкции добавлен обязательный проверенный backup после загрузки индекса и создания admin. Локально прошли backend (37, 1 skip), Telegram (6), backup/restore (16), rollback (3), shell guards, `git diff --check`; отдельно проверил создание, проверку и staging-restore архива корпуса с отсутствующими томами. Production VPS и публичный TLS в рамках ревью не проверялись.
admin merged commit a34f516de8 into main 2026-10-11 20:22:23 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/akyldash#42