2a34ee880a
- /api/dashboard/summary, /api/managers, /api/lead-statuses: были без auth (tenant_id параметром) → auth:sanctum (+tenant); tenant_id из authed-user, не из параметра — закрывает кросс-tenant утечку KPI/списка пользователей - ManagerController: явный where(tenant_id) поверх RLS (BYPASSRLS-роли/тесты) - WebhookUrlGuard + webhooks/test: SSRF-блок private/reserved/loopback IP (cloud-metadata 169.254.169.254 и пр.); update()/delivery — follow-up - TDD: +EndpointAuthHardeningTest(5) +WebhookSsrfGuardTest(10); обновлены Dashboard/Lookups/LeadStatuses тесты под auth - регрессия tests/Feature 960/964 (2 фейла pre-existing: Vite-manifest env + RouteSupplierLeadJobBilling idempotency — оба фейлят и на чистом base) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
59 lines
2.5 KiB
PHP
59 lines
2.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use App\Models\Tenant;
|
||
use App\Models\User;
|
||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||
|
||
uses(DatabaseTransactions::class);
|
||
|
||
/**
|
||
* Go-live security: lookup/дашборд эндпоинты до этого были открыты (без
|
||
* auth-middleware, tenant_id параметром) — любой неавторизованный мог получить
|
||
* KPI/список пользователей произвольного тенанта по ?tenant_id={чужой}.
|
||
*
|
||
* Закрытие: auth:sanctum + tenant, tenant_id из authed-user (как DealController J1).
|
||
*/
|
||
|
||
// --- 401 без авторизации ---
|
||
|
||
test('GET /api/dashboard/summary без авторизации возвращает 401', function () {
|
||
$this->getJson('/api/dashboard/summary')->assertStatus(401);
|
||
});
|
||
|
||
test('GET /api/managers без авторизации возвращает 401', function () {
|
||
$this->getJson('/api/managers')->assertStatus(401);
|
||
});
|
||
|
||
test('GET /api/lead-statuses без авторизации возвращает 401', function () {
|
||
$this->getJson('/api/lead-statuses')->assertStatus(401);
|
||
});
|
||
|
||
// --- cross-tenant: tenant_id из user, параметр чужого тенанта игнорируется ---
|
||
|
||
test('dashboard/summary берёт tenant из authed-user, игнорирует ?tenant_id чужого', function () {
|
||
$mine = Tenant::factory()->create(['balance_rub' => '111.00', 'balance_leads' => 11]);
|
||
$other = Tenant::factory()->create(['balance_rub' => '999.00', 'balance_leads' => 99]);
|
||
$this->actingAs(User::factory()->for($mine)->create());
|
||
|
||
$this->getJson("/api/dashboard/summary?tenant_id={$other->id}")
|
||
->assertOk()
|
||
->assertJsonPath('balance.amount_rub', '111.00');
|
||
});
|
||
|
||
test('managers берёт tenant из authed-user, не отдаёт пользователей чужого тенанта', function () {
|
||
$mine = Tenant::factory()->create();
|
||
$other = Tenant::factory()->create();
|
||
$me = User::factory()->for($mine)->create(['first_name' => 'Свой', 'last_name' => 'Менеджер', 'is_active' => true]);
|
||
User::factory()->for($other)->create(['first_name' => 'Чужой', 'last_name' => 'Менеджер', 'is_active' => true]);
|
||
$this->actingAs($me);
|
||
|
||
$names = $this->getJson("/api/managers?tenant_id={$other->id}")
|
||
->assertOk()
|
||
->json('managers.*.name');
|
||
|
||
expect($names)->toContain('Свой М.');
|
||
expect($names)->not->toContain('Чужой М.');
|
||
});
|