fix(stage): rate-limit 5/min на /connect/token, nginx route /metrics+/swagger, Swagger в Production через IncludeSwagger
Some checks failed
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Has been cancelled
Docker Web / Deploy Web on stage (push) Has been cancelled
Some checks failed
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Has been cancelled
Docker Web / Deploy Web on stage (push) Has been cancelled
Verify-Sprint баги A-D: - A: на stage docker-compose.yml был "RateLimiting__PerMinute=200" — убран, теперь работают дефолты (5/мин, 20/час). 6-я попытка с тем же IP/паролем → 429. - B: web-контейнер nginx не имел location = /metrics → запрос ловился SPA fallback'ом (index.html, 947 байт). Добавлен proxy_pass на api:8080. - C: web-nginx не имел location /swagger/ → swagger.json возвращал SPA HTML. Добавлены /swagger/ + редирект /swagger → /swagger/. - D: Swagger подключался только в Development. Добавлен флаг IncludeSwagger (env IncludeSwagger=true) — Program.cs включает UseSwagger() и в Production если флаг выставлен. На prod admin.food-market.kz флаг не ставим. Проверено через https://test.admin.food-market.kz: - 6 неверных логинов подряд: 1-5 → 400, 6-7 → 429 ✓ - /metrics → 14967 байт prometheus exposition ✓ - /swagger/v1/swagger.json → 422 КБ openapi 3.0.1 ✓ - /swagger/ → swagger-ui (redirect на /swagger/index.html) ✓ Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
a1cccdeef5
commit
ba54155225
|
|
@ -59,6 +59,32 @@ server {
|
||||||
proxy_pass http://api:8080;
|
proxy_pass http://api:8080;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prometheus метрики API. Без этого блока запрос ловится SPA fallback'ом и
|
||||||
|
# возвращает index.html (947 байт) вместо exposition format. На prod-домене
|
||||||
|
# имеет смысл закрыть IP-фильтром (allow 192.168.0.0/16; deny all;), на
|
||||||
|
# stage оставляем открытым — за gateway nginx уже есть auth/TLS-обвязка.
|
||||||
|
location = /metrics {
|
||||||
|
proxy_pass http://api:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Swagger UI + OpenAPI-doc. На контейнере api подключается только когда
|
||||||
|
# IncludeSwagger=true (env-флаг, см. Program.cs). На prod-домене флаг не
|
||||||
|
# выставляем, /swagger вернёт 404 от api — это ожидаемо.
|
||||||
|
location /swagger/ {
|
||||||
|
proxy_pass http://api:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
location = /swagger {
|
||||||
|
return 301 /swagger/;
|
||||||
|
}
|
||||||
|
|
||||||
# Статика изображений товаров — api раздаёт /uploads/... из volume.
|
# Статика изображений товаров — api раздаёт /uploads/... из volume.
|
||||||
location /uploads/ {
|
location /uploads/ {
|
||||||
proxy_pass http://api:8080;
|
proxy_pass http://api:8080;
|
||||||
|
|
|
||||||
42
docs/verify-progress.md
Normal file
42
docs/verify-progress.md
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Верификационный спринт — независимая проверка через домен
|
||||||
|
|
||||||
|
Цель: расхождения между «отчёт говорит [x]» и «реально работает на https://test.admin.food-market.kz».
|
||||||
|
|
||||||
|
Старт: 2026-06-04. Исполнитель: Claude Opus 4.7 (автономный режим).
|
||||||
|
|
||||||
|
## Правила
|
||||||
|
|
||||||
|
- Всё через **https://test.admin.food-market.kz**, не localhost.
|
||||||
|
- Каждая проверка либо `[x] подтверждено + работает`, либо `[x] подтверждено + баг найден + починен + retest зелёный`.
|
||||||
|
- Когда баг: reproduce → fix → build + тесты → `~/deploy-stage.sh` → retest → коммит порцией.
|
||||||
|
- НЕ трогать: global.json, прод admin.food-market.kz, POS WPF.
|
||||||
|
|
||||||
|
## Предварительные баги (найдены пользователем)
|
||||||
|
|
||||||
|
- [ ] **A. Rate-limit на /connect/token не срабатывает** — 7 неверных логинов → все 400, ни одного 429. И через nginx, и напрямую api:8085. Найти/починить middleware/конфиг.
|
||||||
|
- [ ] **B. /metrics через nginx-домен отдаёт SPA HTML** — 947 байт SPA вместо prometheus. Прямой api работает. Routing.
|
||||||
|
- [ ] **C. /swagger/v1/swagger.json через nginx-домен** отдаёт SPA. Аналогично.
|
||||||
|
- [ ] **D. Swagger вообще не подключён на api в Production** — прямой api:8085 /swagger → 404. Включить для Stage.
|
||||||
|
|
||||||
|
## Верификация фич (через домен)
|
||||||
|
|
||||||
|
- [ ] 1. Каталог CRUD через UI (товар + картинка + дубликат).
|
||||||
|
- [ ] 2. Складские документы (Supply/Enter/Loss/Transfer/Inventory/SupplierReturn/Demand) через UI с проверкой Stock.
|
||||||
|
- [ ] 3. RetailSale + CustomerReturn через UI.
|
||||||
|
- [ ] 4. Отчёты Sales/Stock/Profit/ABC через UI с проверкой чисел и экспорта.
|
||||||
|
- [ ] 5. 2FA TOTP через UI (enroll → verify → двухшаговый login → disable).
|
||||||
|
- [ ] 6. Permission-based authz через API (custom role без ProductsEdit → 403).
|
||||||
|
- [ ] 7. OrgAuditLog через UI (3 действия + multi-tenant изоляция).
|
||||||
|
- [ ] 8. SignalR real-time (2 вкладки, продажа в одной → toast/виджет в другой).
|
||||||
|
- [ ] 9. Локализация ru/en (топ-5 страниц).
|
||||||
|
- [ ] 10. Loyalty + Promotions через UI (карта + промокод в чеке).
|
||||||
|
- [ ] 11. PWA (Lighthouse PWA ≥80, offline дашборд + 3 отчёта).
|
||||||
|
- [ ] 12. Mobile 375x667 через Playwright.
|
||||||
|
- [ ] 13. Inventory CSV-импорт через UI.
|
||||||
|
- [ ] 14. POS Sync API с idempotency-key.
|
||||||
|
- [ ] 15. Stock-инвариант под конкуренцией (5 параллельных POST, остаток=3).
|
||||||
|
- [ ] 16. Email-шаблоны через smtp4dev.
|
||||||
|
- [ ] 17. Telegram-бот (или пометить «требует юзера»).
|
||||||
|
- [ ] 18. MinIO storage (картинка в bucket).
|
||||||
|
|
||||||
|
## Журнал
|
||||||
|
|
@ -383,11 +383,13 @@ [new Microsoft.OpenApi.Models.OpenApiSecurityScheme
|
||||||
RequestPath = "/uploads",
|
RequestPath = "/uploads",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
// Swagger/OpenAPI: всегда в Development, в Production — только при IncludeSwagger=true
|
||||||
|
// (используется на stage для дебага без отдельного билда). На prod admin.food-market.kz
|
||||||
|
// флаг не выставляем — sensitive endpoint enumeration.
|
||||||
|
var includeSwagger = app.Environment.IsDevelopment()
|
||||||
|
|| builder.Configuration.GetValue<bool>("IncludeSwagger");
|
||||||
|
if (includeSwagger)
|
||||||
{
|
{
|
||||||
// Swagger/OpenAPI: только в Development. /swagger/v1/swagger.json — JSON-документ,
|
|
||||||
// /swagger — UI. На prod не раскрываем (sensitive endpoint enumeration), на dev
|
|
||||||
// используется фронтом для генерации TS-клиента (`pnpm run gen:api`).
|
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(opts =>
|
app.UseSwaggerUI(opts =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue