make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Artisan; use App\Modules\Identity\Services\LocalDatabaseGuard; use App\Modules\Identity\Services\Permissions; use App\Modules\Identity\Services\Audit; use App\Modules\Workshop\WorkshopWorkflow; use App\Shared\Context\CompanyContext; function ensureWorkshop(bool $ok,string $message): void { if(!$ok) throw new RuntimeException($message); } function workshopFingerprint(string $table,?int $max=null): array { ensureWorkshop((bool)preg_match('/^[a-z_]+$/D',$table),'Unexpected table identifier.'); $where=$max===null?'':' WHERE id <= '.$max; $r=DB::selectOne('SELECT count(*) AS n, md5(COALESCE(string_agg(row_to_json(t)::text, E\'\\n\' ORDER BY row_to_json(t)::text),\'\')) AS h FROM (SELECT * FROM "'.$table.'"'.$where.') t'); return [(int)$r->n,$r->h]; // In-memory comparison only; no record contents exported. } ensureWorkshop(LocalDatabaseGuard::allows(),'Own SGF development application connection required.'); ensureWorkshop($argv===[$argv[0],'--apply-confirmed-080000-and-four-grants'],'Explicit confirmed operation argument required.'); $migration='2026_10_27_080000_create_workshop_resource_records'; $other='2026_10_27_070000_create_simulated_receivables'; $tables=array_map(fn($r)=>$r->tablename,DB::select("SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename")); $newTables=['wo_equipment','wo_orders','wo_entries','wo_decisions','wo_commands','wo_events','wo_outbox']; ensureWorkshop(!DB::table('migrations')->whereIn('migration',[$migration,$other])->exists(),'Expected both migrations pending; refuse changed state.'); ensureWorkshop(!array_intersect($tables,$newTables),'Workshop tables already exist; review state before proceeding.'); $rights=['workshop.view','workshop.open','workshop.assign','workshop.authorize']; $checkScope=function()use($rights): void { ensureWorkshop(DB::table('users')->where(['id'=>1,'name'=>'Osmane Nala','email'=>'nala@tempo.co.mz'])->exists(),'Confirmed opener identity differs.'); ensureWorkshop(DB::table('companies')->where(['id'=>1,'tenant_id'=>1,'name'=>'Tempo Lda'])->exists(),'Confirmed company differs.'); ensureWorkshop(DB::table('units')->where(['id'=>1,'tenant_id'=>1,'company_id'=>1,'name'=>'SEGI'])->exists(),'Confirmed unit differs.'); ensureWorkshop(DB::table('company_memberships')->where(['user_id'=>1,'tenant_id'=>1,'company_id'=>1])->exists(),'Existing membership required.'); $p=app(Permissions::class); $p->require(1,1,1,'company.view');$p->require(1,1,1,'unit.view',1); ensureWorkshop(!DB::table('permission_grants')->where('permission','like','workshop.%')->exists(),'Unexpected existing workshop grants; review first.'); }; $checkScope(); $baseline=[];foreach($tables as $t)$baseline[$t]=workshopFingerprint($t); $max=[];foreach(['permission_grants','identity_audit'] as $t)$max[$t]=(int)DB::table($t)->max('id'); $migrationRows=DB::table('migrations')->orderBy('id')->get()->map(fn($r)=>(array)$r)->all(); $guardHash=hash_file('sha256',base_path('app/Modules/Workshop/WorkshopWorkflow.php')); $secrets=json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/database.json'),true,32,JSON_THROW_ON_ERROR); $owner=config('database.connections.'.config('database.default')); $owner['username']='sgf_dev_owner';$owner['password']=$secrets['dev_owner'];$owner['url']=null; config(['database.connections.sgf_workshop_owner'=>$owner]);unset($owner,$secrets); try { $connection=DB::connection('sgf_workshop_owner'); $identity=$connection->selectOne('SELECT current_database() AS db,current_user AS role,inet_server_port() AS port,rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user'); ensureWorkshop($identity->db==='sgf_tempo_dev'&&$identity->role==='sgf_dev_owner'&&(int)$identity->port===55432&&!$identity->rolsuper&&!$identity->rolcreatedb&&!$identity->rolcreaterole&&!$identity->rolbypassrls,'Unexpected migration owner/destination.'); $connection->transaction(function()use($migration,$other,$baseline,$newTables,$connection): void { $applicationConnection=DB::getDefaultConnection();DB::setDefaultConnection('sgf_workshop_owner'); try { $exit=Artisan::call('migrate',['--database'=>'sgf_workshop_owner','--path'=>'database/migrations/'.$migration.'.php','--force'=>true,'--no-interaction'=>true]); ensureWorkshop($exit===0,'Targeted migration failed.'); foreach($baseline as $t=>$fp)if($t!=='migrations')ensureWorkshop(workshopFingerprint($t)===$fp,'Existing table changed during migration: '.$t); ensureWorkshop(!DB::table('migrations')->where('migration',$other)->exists(),'070000 must remain pending.'); foreach($newTables as $t)ensureWorkshop(DB::table($t)->count()===0,'New workshop table must be empty.'); } finally { DB::setDefaultConnection($applicationConnection); } }); } finally { DB::purge('sgf_workshop_owner');config(['database.connections.sgf_workshop_owner'=>null]); } ensureWorkshop(LocalDatabaseGuard::allows(),'Application connection must remain sgf_dev_app.'); $newMigrationRows=DB::table('migrations')->orderBy('id')->get()->map(fn($r)=>(array)$r)->all(); ensureWorkshop(count($newMigrationRows)===count($migrationRows)+1&&array_slice($newMigrationRows,0,count($migrationRows))===$migrationRows&&end($newMigrationRows)['migration']===$migration,'Unexpected migration ledger delta.'); $grants=DB::transaction(function()use($checkScope,$rights,$baseline,$max): array { DB::table('companies')->where('id',1)->lockForUpdate()->firstOrFail();$checkScope(); $grants=[]; foreach($rights as $right){ $g=['user_id'=>1,'tenant_id'=>1,'company_id'=>1,'unit_id'=>1,'permission'=>$right]; DB::table('permission_grants')->insert($g+['created_at'=>now(),'updated_at'=>now()]); Audit::record('workshop.initial_grant',null,1,1,1,subject:1,details:['permission'=>$right,'reason'=>'Four opener rights specifically authorised; operational use remains blocked.']); $grants[]=$g; } foreach($baseline as $t=>$fp)if($t!=='migrations')ensureWorkshop(workshopFingerprint($t,$max[$t]??null)===$fp,'Prior records changed: '.$t); ensureWorkshop(DB::table('permission_grants')->where('id','>',$max['permission_grants'])->count()===4,'Exactly four new grants required.'); ensureWorkshop(DB::table('identity_audit')->where('id','>',$max['identity_audit'])->where('action','workshop.initial_grant')->count()===4,'Four audit events required.'); ensureWorkshop(DB::table('permission_grants')->where('permission','like','workshop.%')->count()===4,'No technician/verifier grants permitted.'); app(CompanyContext::class)->selectFor(1,1,1,1); $listing=app(WorkshopWorkflow::class)->listing(1); ensureWorkshop($listing['blocked']&&$listing['orders']===[],'Operational listing must remain blocked.'); foreach(['guard','open','record','verify'] as $entry){ try { $w=app(WorkshopWorkflow::class); match($entry){'guard'=>WorkshopWorkflow::guard(),'open'=>$w->open(1,[],'blocked-probe'),'record'=>$w->record(0,1,[],'blocked-probe'),'verify'=>$w->verify(0,1,[],'blocked-probe')}; throw new RuntimeException('Operational command failed to refuse.'); }catch(\Symfony\Component\HttpKernel\Exception\HttpException $e){ensureWorkshop($e->getStatusCode()===403,'Expected operational refusal.');} } return $grants; }); try { DB::select('SELECT sgf_wo_environment()');throw new RuntimeException('SQL environment guard did not refuse.'); } catch(\Illuminate\Database\QueryException $e){ensureWorkshop(str_contains($e->getMessage(),'SGF_WO_TEST_DATABASE_ONLY'),'Unexpected SQL guard response.');} ensureWorkshop(hash_file('sha256',base_path('app/Modules/Workshop/WorkshopWorkflow.php'))===$guardHash,'Operational guard code changed.'); foreach($newTables as $t)ensureWorkshop(DB::table($t)->count()===0,'Workshop tables must remain empty.'); try { \App\Modules\Services\ServiceInvoicing::guard();throw new RuntimeException('Real issuance did not refuse.'); } catch(\Symfony\Component\HttpKernel\Exception\HttpException $e){ensureWorkshop($e->getStatusCode()===403,'Expected real issuance refusal.');} $proof=['date'=>'2026-10-27','database'=>'sgf_tempo_dev','migration_applied'=>$migration,'migration_070000_applied'=>false,'preexisting_tables_checked'=>count($baseline),'prior_records_and_accesses_preserved'=>true,'new_empty_tables'=>$newTables,'new_grants'=>$grants,'audited_new_grants'=>4,'technician_and_verifier_grants'=>0,'application_role'=>'sgf_dev_app','operational_listing_blocked'=>true,'operational_commands_denied'=>['guard'=>403,'open'=>403,'record'=>403,'verify'=>403],'sql_environment_guard_refused'=>true,'real_issuance_blocked'=>true,'guard_source_unchanged'=>true,'real_operations_created'=>false]; file_put_contents(storage_path('app/private/workshop-dev-install-proof.json'),json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR)); echo "Applied only 080000 and four audited grants; prior records preserved, seven new tables empty, 070000 pending, operational/issuance guards verified.\n";