docs(agents): Claude PR4 review — gate PASS, deployment blocked on secrets/access

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ochenstarik-ui 2026-10-19 14:00:49 +07:00
parent 5040ba800c
commit a39f958a98

View file

@ -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 задания.