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:
Дмитрий
2026-05-25 07:35:03 +03:00
parent b2cbc57533
commit 0817c81e67
3 changed files with 32 additions and 30 deletions
+13 -15
View File
@@ -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);
}
}
+12 -8
View File
@@ -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);
});
+7 -7
View File
@@ -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%).
## Активные многоэтапные проекты