This commit is contained in:
2026-11-02 08:06:45 +02:00
parent e4f520092e
commit 2a4169162b
108 changed files with 3793 additions and 88 deletions
+47
View File
@@ -0,0 +1,47 @@
<?php
// Provision only the new, disposable modular-development host. No client lookup.
require __DIR__.'/../vendor/autoload.php';
$app=require __DIR__.'/../bootstrap/app.php';
$app->loadEnvironmentFrom('.env.testing');
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use Illuminate\Support\Facades\DB;
use Tests\Support\IdentityFixture;
use App\Modules\Services\ServicePermissions;
App\Shared\Testing\TestingDatabaseGuard::assertSafe();
$identity=DB::selectOne("SELECT current_setting('cluster_name') AS cluster,current_database() AS db,current_user AS role,inet_server_port() AS port");
abort_unless(preg_match('/^sgf_modular_regression_[a-f0-9]{12}$/D',$identity->cluster) && (int)$identity->port===55439 && $identity->db==='sgf_tempo_test' && $identity->role==='sgf_test_runner',403);
$private=$argv[1]??'';
abort_unless(is_dir(dirname($private)) && basename(dirname($private))==='private',403);
$result=DB::transaction(function(){
$f=IdentityFixture::create('-modular-'.bin2hex(random_bytes(5)));
foreach(['manager'=>'Desenvolvimento — Preparador','reader'=>'Desenvolvimento — Revisor','limited'=>'Desenvolvimento — Consulta'] as $who=>$name){$f[$who]->name=$name;$f[$who]->save();}
DB::table('permission_grants')->where('user_id',$f['limited']->id)->where('permission','access.manage')->delete();
App\Modules\Identity\Services\Audit::record('access.revoked',$f['manager']->id,$f['tenant'],$f['company'],subject:$f['limited']->id,
details:['permission'=>'access.manage','reason'=>'Perfil de consulta sintético novo, sem administração de acessos.']);
foreach(['manager','reader','limited'] as $who){
foreach(['clients.view','services.view','issuer_documents.view','client_documents.view','catalogue_accounting.view','service_fiscal.view'] as $p)IdentityFixture::grant($f[$who]->id,$f['tenant'],$f['company'],$p);
foreach(['service_drafts.view','billing_drafts.view','draft_documents.view','service_invoices.view','service_receivables.view','workshop.view','workshop_billing.view','workshop_corrections.view','direct_costs.view','industrial_costs.view','industrial_budgets.view','industrial_budget_comparisons.view'] as $p)IdentityFixture::grant($f[$who]->id,$f['tenant'],$f['company'],$p,$f['unit']);
}
foreach(ServicePermissions::AREAS as $area)foreach(['create','edit'] as $action)IdentityFixture::grant($f['manager']->id,$f['tenant'],$f['company'],"$area.$action",ServicePermissions::unitScoped($area)?$f['unit']:null);
foreach(['catalogue_accounting.propose','service_fiscal.propose'] as $p)IdentityFixture::grant($f['manager']->id,$f['tenant'],$f['company'],$p);
foreach(['catalogue_accounting.approve','service_fiscal.approve'] as $p)IdentityFixture::grant($f['reader']->id,$f['tenant'],$f['company'],$p);
foreach(['workshop.open','workshop.assign','workshop.authorize','workshop_billing.prepare','workshop_billing.generate','workshop_corrections.request','workshop_corrections.apply','direct_costs.prepare','industrial_costs.prepare','industrial_budgets.prepare','industrial_budget_comparisons.prepare','service_receivables.prepare','service_receivables.allocate','service_receivables.correction_request'] as $p)IdentityFixture::grant($f['manager']->id,$f['tenant'],$f['company'],$p,$f['unit']);
foreach(['workshop_billing.review','workshop_corrections.review','direct_costs.validate','industrial_costs.validate','industrial_budgets.validate','service_receivables.confirm','service_receivables.reconcile','service_receivables.correction_approve'] as $p)IdentityFixture::grant($f['reader']->id,$f['tenant'],$f['company'],$p,$f['unit']);
// Pending example intentionally has no module association.
$pending=DB::table('a_clients')->insertGetId(['tenant_id'=>$f['tenant'],'company_id'=>$f['company'],'unit_id'=>null,'name'=>'Registo sintético pendente de associação','version'=>1,'data'=>'{}','created_at'=>now(),'updated_at'=>now()]);
foreach(['manager','reader','limited'] as $who)App\Modules\Identity\Services\Audit::record('development.profile.created',$f['manager']->id,$f['tenant'],$f['company'],$f['unit'],$f[$who]->id,details:['reason'=>'Perfil sintético isolado de '.$who.'; descoberta não concede operações.']);
return ['tenant_id'=>$f['tenant'],'company_id'=>$f['company'],'unit_id'=>$f['unit'],'pending_record_id'=>$pending,
'profiles'=>array_map(fn($who)=>['role'=>$who==='manager'?'preparador':($who==='reader'?'revisor':'consulta'),'id'=>$f[$who]->id,'email'=>$f[$who]->email],['manager','reader','limited']),
'password'=>$f['password']];
});
file_put_contents($private,json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR));
unset($result['password']);
$profiles=implode(',',array_map(fn($p)=>$p['id'].':'.$result['tenant_id'].':'.$result['company_id'],$result['profiles']));
$env=file_get_contents(base_path('.env.testing'));
$env=preg_replace('/^APP_ENV=.*$/m','APP_ENV=browser-testing',$env);
$env=preg_replace('/^SESSION_DRIVER=.*$/m','SESSION_DRIVER=file',$env);
$env.="\nSESSION_COOKIE=sgf_modular_development\nSGF_DEVELOPMENT_PROFILES={$profiles}\n";
file_put_contents(base_path('.env.browser-testing'),$env);
echo json_encode(['configured'=>true,'database_identity'=>(array)$identity,'development'=>$result,'module_count'=>6,'pending_associations_unchanged'=>true],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL;