Безопасность довёл до ума — Cursor-генерацию переписал руками. IDOR закрыл, CSRF задушил, refresh rotation теперь как надо. HSTS на staging, ENABLE_DOCS=false, install.env recovery протестил. Backend: - jwt_denylist + auth_epoch: мгновенный revoke access JWT (logout/block/reset) - auth/admin/users: bump epoch, logout с Bearer, forgot_password skip для blocked - install_secrets: путь всегда apps/api/data/secrets/ (bootstrap из корня не ломает Docker) - seed: SEED_DEMO_USERS=false на prod/staging - тесты: jwt revoke, integration, coverage gate 90% Frontend: - logout шлёт Bearer, обработка TOKEN_REVOKED - guards TypeScript fix - E2E: blocked user → 401 сразу после block Infra: - staging/prod compose, TLS nginx, deploy-скрипты - k6 §17.2, backup/health/smoke scripts Docs: - docs/ на русском: project, security, deploy, release (старые md слили) - README короткий + план ТЗ + стандартные логины dev Код готов к плаванию. Капитан может идти писать фронт.
114 lines
3.0 KiB
Markdown
114 lines
3.0 KiB
Markdown
# Релиз и QA gates
|
|
|
|
Перед production не «авось прокатит», а чеклист из ТЗ §17. Если что-то красное — сначала staging, потом prod. Живёт один раз.
|
|
|
|
## Pipeline
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
CI[CI green] --> ST[Staging + TLS]
|
|
ST --> E2E[E2E 11/11]
|
|
ST --> K6[k6 pass]
|
|
ST --> ZAP[ZAP 0 High/Crit]
|
|
ST --> LH[Lighthouse ≥ 85]
|
|
E2E --> PROD[Production deploy]
|
|
K6 --> PROD
|
|
ZAP --> PROD
|
|
LH --> PROD
|
|
PROD --> SM[smoke-prod.sh]
|
|
SM --> DNS[DNS cutover]
|
|
DNS --> MON[24h мониторинг]
|
|
```
|
|
|
|
## Регрессия E2E
|
|
|
|
**Последний локальный прогон:** 2026-07-14 — backend 137 / 90.43% cov, frontend 46.
|
|
|
|
### Staging
|
|
|
|
```bash
|
|
E2E_BASE_URL=https://staging.example.com E2E_START_API=false pnpm --filter web e2e
|
|
```
|
|
|
|
| # | Сценарий | Local | Staging |
|
|
|---|----------|:-----:|:-------:|
|
|
| 1 | Landing hero, reduced-motion | ☐ | ☐ |
|
|
| 2 | Register → verify → login → profile → logout | ☐ | ☐ |
|
|
| 3 | Forgot → reset → login | ☐ | ☐ |
|
|
| 4 | Admin publish → public slug | ☐ | ☐ |
|
|
| 5 | Block user → login denied | ☐ | ☐ |
|
|
| 6 | Pending → нет `/profile` | ☐ | ☐ |
|
|
| 7 | Refresh rotation | ☐ | ☐ |
|
|
| 8 | IDOR user A ≠ user B | ☐ | ☐ |
|
|
| 9 | Admin не блокирует себя / last admin | ☐ | ☐ |
|
|
| 10 | Avatar: bad MIME / size / SVG | ☐ | ☐ |
|
|
| 11 | Block → access JWT 401 TOKEN_REVOKED | ☐ | ☐ |
|
|
|
|
### Локально
|
|
|
|
```bash
|
|
pnpm --filter web e2e # API :8001, Vite :5175
|
|
```
|
|
|
|
## k6 (§17.2)
|
|
|
|
```bash
|
|
k6 run infra/k6/mvp-load-test.js -e BASE_URL=https://staging.example.com
|
|
```
|
|
|
|
| Параметр | Порог |
|
|
|----------|-------|
|
|
| VU / ramp | 50 / 5 min |
|
|
| Mix | 35% list, 25% login, 20% me, 10% refresh, 10% slug |
|
|
| p95 | < 300 ms |
|
|
| Errors | < 1% |
|
|
|
|
## OWASP ZAP
|
|
|
|
```bash
|
|
docker run --rm -v "$(pwd):/zap/wrk:rw" -t ghcr.io/zap/zaproxy:stable \
|
|
zap-baseline.py -t https://staging.example.com -r zap-report.html
|
|
```
|
|
|
|
| Severity | Pass |
|
|
|----------|------|
|
|
| High, Critical | **0** |
|
|
|
|
Medium/Low — review руками. `zap-report.html` — в архив релиза.
|
|
|
|
## Lighthouse
|
|
|
|
```bash
|
|
npx lighthouse https://staging.example.com \
|
|
--preset=mobile --only-categories=performance \
|
|
--output=json --output-path=./lighthouse-report.json
|
|
```
|
|
|
|
| Метрика | ≥ |
|
|
|---------|---|
|
|
| Performance (mobile, `/`) | 85 |
|
|
|
|
Не прошло — hero video `preload="none"`, font swap, меньше JS на лендинге.
|
|
|
|
## Release gates (сводка)
|
|
|
|
- [ ] CI green на `main`
|
|
- [ ] E2E 11/11 на staging
|
|
- [ ] k6 pass
|
|
- [ ] ZAP 0 High/Critical
|
|
- [ ] Lighthouse ≥ 85
|
|
- [ ] [security.md](./security.md) staging-пункты
|
|
- [ ] `./infra/scripts/smoke-prod.sh` на prod
|
|
- [ ] DNS cutover + rollback plan (previous tag)
|
|
|
|
## CI локально
|
|
|
|
```bash
|
|
pnpm lint && pnpm typecheck
|
|
cd apps/api && python -m mypy app
|
|
pnpm --filter web test:ci
|
|
cd apps/api && python -m pytest --cov=app --cov-fail-under=90
|
|
```
|
|
|
|
Полный pipeline: `.github/workflows/ci.yml`.
|