3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-08-18 11:15:42 +00:00
Files
snipe-it/tests/Feature/Reporting/AcceptanceReportFmcsScopeTest.php

128 lines
5.1 KiB
PHP

<?php
namespace Tests\Feature\Reporting;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\User;
use Tests\TestCase;
/**
* Regression coverage for the FMCS scope gap reported by Arpit Jain
* (arpitjain099) on 2026-08-02. Both getAssetAcceptanceReport (the page)
* and postAssetAcceptanceReport (the CSV export) ran
* CheckoutAcceptance::pending() with no company scope. CheckoutAcceptance
* has no company_id column and does not use CompanyableTrait /
* CompanyableChildTrait, so it is not covered by the CompanyableScope
* global scope. Companion read-side bug to GHSA-p5wx-p3vv-g6p2, which
* fixed the same scope gap on the mutating actions.
*
* Both read paths now filter their result set through
* currentUserCanAccessAcceptance(), matching the pattern the mutating
* actions on the same page use.
*/
class AcceptanceReportFmcsScopeTest extends TestCase
{
private function seedPendingAcceptanceOwnedBy(Company $company): array
{
$asset = Asset::factory()->create(['company_id' => $company->id, 'name' => 'Asset-'.$company->id]);
$acceptance = CheckoutAcceptance::factory()->pending()->for($asset, 'checkoutable')->create();
return [$asset, $acceptance];
}
public function test_page_render_hides_other_company_pending_acceptances_under_fmcs()
{
$this->settings->enableMultipleFullCompanySupport();
[$companyA, $companyB] = Company::factory()->count(2)->create();
[$assetA] = $this->seedPendingAcceptanceOwnedBy($companyA);
[$assetB] = $this->seedPendingAcceptanceOwnedBy($companyB);
$reporterA = User::factory()->canViewReports()->forCompany($companyA)->create();
$response = $this->actingAs($reporterA)
->get(route('reports/unaccepted_assets'))
->assertOk();
$this->assertStringContainsString($assetA->name, $response->getContent());
$this->assertStringNotContainsString($assetB->name, $response->getContent());
}
public function test_csv_export_hides_other_company_pending_acceptances_under_fmcs()
{
$this->settings->enableMultipleFullCompanySupport();
[$companyA, $companyB] = Company::factory()->count(2)->create();
[$assetA] = $this->seedPendingAcceptanceOwnedBy($companyA);
[$assetB] = $this->seedPendingAcceptanceOwnedBy($companyB);
$reporterA = User::factory()->canViewReports()->forCompany($companyA)->create();
$response = $this->actingAs($reporterA)
->post(route('reports/export/unaccepted_assets'))
->assertOk();
$body = $response->getContent();
$this->assertStringContainsString($assetA->name, $body);
$this->assertStringNotContainsString($assetB->name, $body);
}
public function test_superuser_sees_all_company_pending_acceptances_in_page()
{
$this->settings->enableMultipleFullCompanySupport();
[$companyA, $companyB] = Company::factory()->count(2)->create();
[$assetA] = $this->seedPendingAcceptanceOwnedBy($companyA);
[$assetB] = $this->seedPendingAcceptanceOwnedBy($companyB);
$superuser = User::factory()->superuser()->forCompany($companyA)->create();
$response = $this->actingAs($superuser)
->get(route('reports/unaccepted_assets'))
->assertOk();
$this->assertStringContainsString($assetA->name, $response->getContent());
$this->assertStringContainsString($assetB->name, $response->getContent());
}
public function test_superuser_sees_all_company_pending_acceptances_in_csv()
{
$this->settings->enableMultipleFullCompanySupport();
[$companyA, $companyB] = Company::factory()->count(2)->create();
[$assetA] = $this->seedPendingAcceptanceOwnedBy($companyA);
[$assetB] = $this->seedPendingAcceptanceOwnedBy($companyB);
$superuser = User::factory()->superuser()->forCompany($companyA)->create();
$response = $this->actingAs($superuser)
->post(route('reports/export/unaccepted_assets'))
->assertOk();
$body = $response->getContent();
$this->assertStringContainsString($assetA->name, $body);
$this->assertStringContainsString($assetB->name, $body);
}
public function test_fmcs_disabled_leaves_report_unscoped()
{
// With FMCS off the helper short-circuits and every row passes.
// Guard against future refactors that accidentally add scoping on
// installs that do not have FMCS enabled.
[$companyA, $companyB] = Company::factory()->count(2)->create();
[$assetA] = $this->seedPendingAcceptanceOwnedBy($companyA);
[$assetB] = $this->seedPendingAcceptanceOwnedBy($companyB);
$reporterA = User::factory()->canViewReports()->forCompany($companyA)->create();
$response = $this->actingAs($reporterA)
->get(route('reports/unaccepted_assets'))
->assertOk();
$this->assertStringContainsString($assetA->name, $response->getContent());
$this->assertStringContainsString($assetB->name, $response->getContent());
}
}