From a39f958a984abcf5ee28344326c29321236c8e0d Mon Sep 17 00:00:00 2001 From: ochenstarik-ui <267932263+ochenstarik-ui@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:00:49 +0700 Subject: [PATCH] =?UTF-8?q?docs(agents):=20Claude=20PR4=20review=20?= =?UTF-8?q?=E2=80=94=20gate=20PASS,=20deployment=20blocked=20on=20secrets/?= =?UTF-8?q?access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ...2026-10-19-stage1-pr4-review-and-deploy.md | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 agents/claude/done/2026-10-19-stage1-pr4-review-and-deploy.md diff --git a/agents/claude/done/2026-10-19-stage1-pr4-review-and-deploy.md b/agents/claude/done/2026-10-19-stage1-pr4-review-and-deploy.md new file mode 100644 index 0000000..a04dffd --- /dev/null +++ b/agents/claude/done/2026-10-19-stage1-pr4-review-and-deploy.md @@ -0,0 +1,86 @@ +# Claude — независимая проверка PR #4 и развёртывание Stage1 (ЧАСТИЧНЫЙ ОТЧЁТ) + +Дата: 2026-10-19, домашний сервер (`server`, 10.77.0.3). Задание: +`agents/claude/inbox/2026-10-19-stage1-pr4-review-and-deploy.md`. + +## SHA +- PR: https://git.ochenstarik.ru/ochenstarik/randomayzer/pulls/4 +- Base на момент проверки: `13606008f16f53d50845cd7389a4c5d3813fec12`. Отличие от base в handoff (`52fb758`) — + только мой документ `agents/codex/inbox/2026-10-19-stage1-completion.md`. +- **Reviewed SHA: `5040ba800c5d87f8405997fb854c719e93932fec`**: runtime-файлы идентичны `cce70c0`, шаблоны proxy — + `c5ede46`. Между `930e6ee` и `5040ba8` только handoff-документы (проверено `git diff --name-only`). +- Merge SHA, deployed SHA, image ID — **нет, развёртывание не выполнялось** (см. блокеры). + +## 1. Gate на reviewed SHA (отдельный worktree) + +| Команда | exit | Результат | +|---|---|---| +| `npm ci` | 0 | 449 packages | +| `npx prisma generate` | 0 | Prisma Client 5.22.0 | +| `npm test` | 0 | 63 files, **380/380** | +| `npx tsc --noEmit` | 0 | без ошибок | +| `npm run lint` | 0 | 0 errors, 6 warnings | +| `npm run build` | 0 | Compiled successfully | +| `npm audit --omit=dev` | 0 | found 0 vulnerabilities (только production deps; dev-дерево не заявляется чистым) | + +## 2. R2 — чистая PostgreSQL 16 (127.0.0.1:55439, новый volume `randomayzer-integration-pgdata`) +- До миграций: 0 таблиц в `public`. +- `prisma migrate deploy`: exit 0, 3 миграции (`20260818000000_initial`, `…120000_ownership_invariant`, + `20260821120000_persistent_auth_stores`). +- `npm run test:integration`: exit 0, **12/12**. +- `prisma migrate diff --from-url … --to-schema-datamodel … --exit-code`: exit 0, «No difference detected». +- Контейнер остановлен (`down`), свой тестовый volume удалён. Чужие volumes не трогались. +- `agents/codex/notes/validate-r5-templates.sh`: exit 0 — синтаксис Caddy 2.8 и HAProxy 3.0 на fake fixture. + **Это не приёмка живого VPS.** + +## 3. Ревью кода + +| Область | Итог | +|---|---| +| Seed-исключение | Только 4 assertion длины в `tests/randomizer.test.ts` и `tests/seed-precommit-gate.test.ts`, 32→64 hex — строже, не слабее. `generateCryptoSecureSeed` = 32 байта. HMAC, proof format и snapshot hash не тронуты. В `src/` нет валидации длины seed → прежние 32-hex розыгрыши продолжают проверяться. Совпадает с `agents/codex/inbox/2026-10-19-seed-owner-authorization.md`. | +| Malformed VK records (прежний HIGH) | **CLOSED** на reviewed SHA. `vk-provider.ts`/`vk-client.ts`: строгая проверка shape/ID/типов профилей, дублей, `count`, размера страницы, смены total и раннего конца → `VkIncompleteDataError`, «No result was saved». | +| Partial participant saves | Замена участников в одной `prisma.$transaction` (`deleteMany` + вставка) — частичного сохранения нет. | +| Mock-smoke (прежний MEDIUM) | **CLOSED**: preview отдаёт `providerMode: LIVE/MOCK` (`instanceof VkProvider`); smoke опирается на маркер. | +| Proxy socket-peer | `tools/production-transport.cjs`: все `x-forwarded-*`, `forwarded`, `x-real-ip`, `cf-connecting-ip` удаляются; доверие только при socket peer == `TRUSTED_PROXY_IP`. Значение — только `10.77.0.1`, в local запрещено. XFF принимается только как один IP; proto https — только от доверенного peer. | +| Профили | local: только `http://localhost/127.0.0.1/[::1]`; strict: только https. `VK_REDIRECT_URI` обязан быть `${origin}/api/auth/vk/callback`. CSRF в production сверяет полный origin. Secure cookie по профилю, HttpOnly, SameSite=Lax. | +| Compose | БД без host-порта, сеть `internal: true`; app `127.0.0.1:3100` (+`10.77.0.3:3100` в domain overlay), `cap_drop: ALL`, `no-new-privileges`, лимиты app 1g/1.5, PG 512m/1.0, `user: node`/`postgres`. | +| Backup/restore | `umask 077`, проверка 0600 env, `.partial` + `pg_restore --list`, восстановление в отдельную drill-БД с удалением, retention 14 дней. | +| Caddy template | basic_auth, `-Authorization` к upstream, вычистка `X-Real-IP`/`Forwarded`/`CF-Connecting-IP`, лимит тела 1 МБ, таймауты. | + +### Findings +- **CRITICAL/HIGH: не найдено.** +- **MEDIUM (проверить вживую):** если `krona-proxy-mux` пропускает TLS к Caddy по SNI без PROXY protocol, + `{remote_host}` у Caddy = адрес контейнера HAProxy → приложение видит всех клиентов с одного IP. Тогда rate limit + по IP общий, аудит-IP неверен. Для сайта одного пользователя не блокирует; решение — PROXY protocol v2 + HAProxy→Caddy, если он уже используется для других сайтов, иначе принять как debt. +- **MEDIUM (функционально, вживую):** на активном посте VK при пагинации может вернуть дубль ID + (лайк между страницами) → импорт отказывает целиком. Это fail-closed по дизайну, но живой импорт может часто + требовать повтора. Проверить в G на реальном посте; при частых отказах — отдельная задача (повтор/снимок). +- **LOW (известные):** COMMUNITY adminDetection metadata (маршруты не позволяют неподдерживаемую проверку); + нет HTTP→HTTPS redirect при только HTTP-01 маршруте. Решение — оставить LOW до живой проверки, не открывать + обычный HTTP к приложению. +- **LOW (новое):** ежедневные дампы лежат на том же системном SSD (занят на 85%, ресурс износа 19%) — + не offsite. Согласуется с решением владельца отложить offsite-бэкапы. + +## 4. Предусловия развёртывания (проверено) +- Порт 3100 свободен; `krona-wg` 10.77.0.3/24 поднят; RAM свободно ~35 ГБ; диск `/` 85%. +- WG peer `10.77.0.1` = VPS 178.212.13.102 (совпадает SSH host key ed25519, проверено ранее 19.10). +- DNS `random.ochenstarik.ru` → 178.212.13.102 по публичным резолверам (Google, Cloudflare DoH); + домашний роутер `192.168.1.1` отдаёт устаревший 185.26.122.80 — проверять через публичный DNS. +- **SSH на VPS для Claude: нет** (`krona@10.77.0.1: Permission denied (publickey)`). + +## Блокеры (развёртывание не начиналось) +1. **Секреты (владелец):** 0600-файл production env вне Git с VK ID `VK_APP_ID`/`VK_CLIENT_SECRET`, + `VK_SERVICE_TOKEN`, `AUTH_SECRET`, `TOKEN_ENCRYPTION_KEY`, `POSTGRES_PASSWORD`. Молча не генерирую. +2. **VK ID кабинет (владелец):** redirect URI `http://localhost:3100/api/auth/vk/callback` и + `https://random.ochenstarik.ru/api/auth/vk/callback`. Поддержка localhost этим приложением не гарантирована. +3. **VPS (владелец):** SSH-доступ для Claude или выполнение раздела 6 runbook владельцем. Без него R5 BLOCKED. +4. **Живой VK:** тестовый аккаунт, публичный пост с лайками и комментариями, restricted post, группа для подписки. + A–M: все **BLOCKED** до п. 1–2. + +## Вердикты +- **PR review:** PASS (без CRITICAL/HIGH; 2 MEDIUM на живую проверку, LOW перечислены). Рекомендую merge в main. +- **Домашний deployment:** не выполнен — BLOCKED (секреты). +- **VPS/domain:** не выполнен — BLOCKED (доступ, секреты). +- **Live VK A–M:** не выполнялось — BLOCKED. +- **Рекомендация координатору:** этап не закрыт; после секретов и доступа — шаги 3–6 задания.