Files
SGF/scripts/ledger-cost-correction-security.php
T
2026-11-04 09:37:20 +02:00

8 lines
2.9 KiB
PHP

<?php
use Illuminate\Support\Facades\DB;
use App\Shared\Context\CompanyContext;
$output=$s['root'].'/cost-correction-security.json';if(file_exists($output)||DB::table('gl_corrections')->exists())throw new LogicException('Fresh correction security proof required');$checks=0;$ok=function($v,$m)use(&$checks){$checks++;if(!$v)throw new LogicException($m);};
foreach(['unit','company','tenant'] as $kind){DB::beginTransaction();try{$u=$enter('prepare');$company=$kind==='unit'?DB::table('companies')->where('id',$scope['company_id'])->first():($kind==='company'?DB::table('companies')->where('tenant_id',$scope['tenant_id'])->where('id','<>',$scope['company_id'])->first():DB::table('companies')->where('tenant_id','<>',$scope['tenant_id'])->first());$unit=DB::table('units')->insertGetId(['tenant_id'=>$company->tenant_id,'company_id'=>$company->id,'name'=>'Rollback-only correction foreign '.$kind,'created_at'=>now(),'updated_at'=>now()]);if(!DB::table('company_memberships')->where(['tenant_id'=>$company->tenant_id,'company_id'=>$company->id,'user_id'=>$u->id])->exists())DB::table('company_memberships')->insert(['tenant_id'=>$company->tenant_id,'company_id'=>$company->id,'user_id'=>$u->id]);foreach(['company.view'=>null,'unit.view'=>$unit,'workshop.view'=>$unit,'direct_costs.view'=>$unit,'general_ledger.view'=>$unit,'general_ledger.correct_prepare'=>$unit] as $right=>$v)Tests\Support\IdentityFixture::grant($u->id,$company->tenant_id,$company->id,$right,$v);app(CompanyContext::class)->selectFor($u->id,$company->tenant_id,$company->id,$unit);$caught=false;try{$ledger->engine($u)->command('correct-prepare',$correctionBody,(string)Illuminate\Support\Str::uuid());}catch(DomainException|Symfony\Component\HttpKernel\Exception\HttpException){$caught=true;}$ok($caught,'Eligible foreign '.$kind.' cannot correct original');}finally{while(DB::transactionLevel())DB::rollBack();$enter('prepare');}}
foreach(['workshop.view','direct_costs.view','general_ledger.view','general_ledger.correct_prepare'] as $right){DB::beginTransaction();try{DB::table('permission_grants')->where($scope)->where('user_id',$g['actors']['prepare'])->where('permission',$right)->delete();$caught=false;try{$captureCorrection();}catch(DomainException|Symfony\Component\HttpKernel\Exception\HttpException|Illuminate\Auth\Access\AuthorizationException){$caught=true;}$ok($caught,'Revoked '.$right.' refuses correction before capture');}finally{while(DB::transactionLevel())DB::rollBack();$enter('prepare');}}
$ok($originalsIntact()&&!DB::table('gl_corrections')->exists(),'Security probes preserve all original/source/outbox/rights state');file_put_contents($output,json_encode(['passed'=>true,'checks'=>$checks,'eligible_foreign_tenant_company_unit_refused'=>true,'four_live_rights_revalidated'=>true,'rollback_only'=>true,'source_outbox_rights_unchanged'=>true],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo "Correction security: $checks checks, eligible foreign contexts/live rights refused, originals preserved.\n";