fix(admin): снять 503-замок saas-admin зоны — защиту держит nginx basic-auth
EnsureSaasAdmin fail-closed 503 вне dev/testing → вся админка на боевом liderra.ru недоступна (все /api/admin/* падали). Настоящий saas-admin SSO (Yandex 360) ещё не готов (Б-1 + DO-4), но держать зону наглухо закрытой нельзя — заказчику нужна админка. Стопгэп (выбор заказчика): защита /admin + /api/admin/* переносится на nginx (отдельный HTTP Basic Auth, /etc/nginx/.htpasswd-admin), middleware зону больше не закрывает. Тест production-кейса переведён с 503 на 200. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,28 +11,26 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
/**
|
||||
* Гейт SaaS-admin зоны (/api/admin/*) — audit-находка J2.
|
||||
*
|
||||
* СТАБ (Sprint 3F): полноценная авторизация saas-admin требует Yandex 360
|
||||
* SSO-входа, который гейтится Б-1 (регистрация ООО) + DO-4. До их закрытия
|
||||
* реального механизма аутентификации нет.
|
||||
* СТОПГЭП (2026-05-25): защита боевой админ-зоны (/admin + /api/admin/*)
|
||||
* перенесена на уровень nginx — отдельный HTTP Basic Auth с собственным
|
||||
* паролем (`/etc/nginx/.htpasswd-admin`, location ^~ /admin и ^~ /api/admin).
|
||||
* Поэтому middleware больше не закрывает зону на проде: дверь держит nginx.
|
||||
*
|
||||
* Поведение стаба:
|
||||
* - dev / testing (local, testing) → пропускаем. Admin-панель работает на
|
||||
* dev; admin_user_id передаётся параметром (трейт ResolvesAdminUserId).
|
||||
* - прочие окружения (production / staging) → fail-closed 503: зона
|
||||
* закрыта до подключения реального SSO. Явный 503 лучше, чем тихо
|
||||
* открытый /api/admin/* в проде.
|
||||
* Ранее (Sprint 3F) здесь был fail-closed 503 вне dev/testing — он закрывал
|
||||
* всю админку на проде наглухо, т.к. настоящий saas-admin SSO (Yandex 360)
|
||||
* ещё не готов (гейтится Б-1 + DO-4). Замок 503 снят осознанно: оголять
|
||||
* /api/admin/* в интернет нельзя, но nginx-пароль её прикрывает.
|
||||
*
|
||||
* TODO (после Б-1 + DO-4): заменить на проверку Yandex 360 SSO-сессии
|
||||
* saas-admin (отдельный guard) + роль (compliance и т.п. где требуется).
|
||||
* admin_user_id для audit-trail по-прежнему резолвится трейтом
|
||||
* ResolvesAdminUserId (стаб super_admin) — это отдельная зона.
|
||||
*
|
||||
* TODO (после Б-1 + DO-4): заменить nginx-дверь на настоящий saas-admin
|
||||
* guard (Yandex 360 SSO-сессия + роль), вернуть проверку в это middleware.
|
||||
*/
|
||||
class EnsureSaasAdmin
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (! app()->environment('local', 'testing')) {
|
||||
abort(503, 'SaaS-admin авторизация не настроена (ожидает Б-1 + DO-4).');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,25 @@ declare(strict_types=1);
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* J2 (Sprint 3F) — стаб-гейт SaaS-admin зоны.
|
||||
* J2 (Sprint 3F) — гейт SaaS-admin зоны.
|
||||
*
|
||||
* EnsureSaasAdmin на /api/admin/*: dev/testing пропускает (admin-панель
|
||||
* работает на dev), прочие окружения — fail-closed 503 до подключения
|
||||
* реального Yandex 360 SSO (TODO под Б-1+DO-4).
|
||||
* EnsureSaasAdmin на /api/admin/*: пропускает запрос во ВСЕХ окружениях.
|
||||
* Защита боевой админ-зоны (/admin + /api/admin/*) перенесена на nginx
|
||||
* (HTTP Basic Auth, отдельный пароль — /etc/nginx/.htpasswd-admin), потому
|
||||
* что настоящий saas-admin SSO (Yandex 360) ещё не готов (Б-1 + DO-4).
|
||||
* Ранее middleware fail-closed 503 вне dev/testing — это закрывало всю
|
||||
* админку на проде наглухо; стопгэп заменил замок на nginx-дверь.
|
||||
*/
|
||||
uses(DatabaseTransactions::class);
|
||||
|
||||
test('/api/admin/* пропускается на testing-окружении (стаб permissive)', function () {
|
||||
// Дефолтное тестовое окружение = testing → middleware пропускает.
|
||||
test('/api/admin/* пропускается на testing-окружении', function () {
|
||||
$this->getJson('/api/admin/tenants')->assertStatus(200);
|
||||
});
|
||||
|
||||
test('/api/admin/* возвращает 503 вне dev/testing (стаб fail-closed)', function () {
|
||||
test('/api/admin/* пропускается и на production (замок 503 снят, дверь держит nginx)', function () {
|
||||
$this->app->detectEnvironment(fn () => 'production');
|
||||
|
||||
$this->getJson('/api/admin/tenants')->assertStatus(503);
|
||||
// Раньше тут был 503. Теперь приложение зону не закрывает — её держит
|
||||
// nginx basic-auth (стопгэп до реального Yandex 360 SSO).
|
||||
$this->getJson('/api/admin/tenants')->assertStatus(200);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Brain Status (auto-generated)
|
||||
|
||||
Last updated: 2026-05-25T03:31:18.491Z
|
||||
Last updated: 2026-05-25T04:31:41.337Z
|
||||
|
||||
| Контролёр | Состояние | Детали |
|
||||
|---|---|---|
|
||||
@@ -8,13 +8,13 @@ Last updated: 2026-05-25T03:31:18.491Z
|
||||
| C2 Cross-ref consistency | 🔴 | Update cross-refs in offending files. |
|
||||
| C3 Observer-of-observer | ✅ | [observer-of-observer] OK — last read 0 week(s) ago |
|
||||
| C4 Сигнальный статус | ✅ | This file (self-reference) |
|
||||
| C5 Observer-coverage | ⚠️ | 339 episode(s) this month · Stop-hook + post-commit OK · 21 missed activation(s) — see /brain-retro |
|
||||
| C5 Observer-coverage | ⚠️ | 341 episode(s) this month · Stop-hook + post-commit OK · 21 missed activation(s) — see /brain-retro |
|
||||
| C6 Chain map sync | ✅ | [chain-map-checker] OK — 16 chains in sync |
|
||||
|
||||
## Метрики (информационные, не алерты)
|
||||
|
||||
- Observer evidence: 339 episodes this month, 0 observer_error markers, 31 PII matches before filter
|
||||
- Legacy v1 episodes (not in factor analysis): 200
|
||||
- Observer evidence: 341 episodes this month, 0 observer_error markers, 31 PII matches before filter
|
||||
- Legacy v1 episodes (not in factor analysis): 202
|
||||
- Last /brain-retro: 0 day(s) ago
|
||||
- Использование узлов: см. `/brain-retro` (раз в спринт). missed_activations: 21. **Неиспользованные узлы — не алерт, если профильной задачи не было** (Pravila §16.4 v1.36; capability-readiness; см. memory `feedback_brain_unused_tools_not_problem` — outside-repo memory store).
|
||||
|
||||
@@ -27,14 +27,14 @@ Baseline дисциплины роутера (этап 2 router discipline overh
|
||||
| analysis | 15 | 46.7% | 26.7% |
|
||||
| monitoring | 12 | 0.0% | 0.0% |
|
||||
| bugfix | 10 | 40.0% | 40.0% |
|
||||
| planning | 9 | 11.1% | 22.2% |
|
||||
| feature | 9 | 22.2% | 0.0% |
|
||||
| planning | 7 | 14.3% | 14.3% |
|
||||
| refactor | 1 | 0.0% | 0.0% |
|
||||
| cleanup | 1 | 0.0% | 0.0% |
|
||||
|
||||
Router step distribution: 1: 139, 2: 117, 3: 37, 5: 41
|
||||
Router step distribution: 1: 139, 2: 118, 3: 37, 5: 42
|
||||
|
||||
Boundaries applied (ADR / границы): 47 of 334 эпизодов (14.1%).
|
||||
Boundaries applied (ADR / границы): 47 of 336 эпизодов (14.0%).
|
||||
|
||||
## Активные многоэтапные проекты
|
||||
|
||||
|
||||
Reference in New Issue
Block a user