$value)if(preg_match('/^(APP_|DB_|SGF_|SESSION_|CACHE_|QUEUE_|BCRYPT_)/',$key)){putenv($key.'='.$value);$_ENV[$key]=$value;$_SERVER[$key]=$value;} foreach(['APP_BASE_PATH'=>$repo,'APP_CONFIG_CACHE'=>$private.'/config.php','APP_ROUTES_CACHE'=>$private.'/routes.php','APP_SERVICES_CACHE'=>$private.'/services.php','APP_PACKAGES_CACHE'=>$private.'/packages.php','SESSION_DRIVER'=>'array','CACHE_STORE'=>'array'] as $key=>$value){putenv($key.'='.$value);$_ENV[$key]=$value;$_SERVER[$key]=$value;} require $repo.'/vendor/autoload.php';$app=require $repo.'/bootstrap/app.php';$app->addAbsoluteCachePathPrefix('C:');$app->useStoragePath($private.'/storage');foreach(['logs','framework/views','framework/sessions','framework/cache/data'] as $dir)mkdir($private.'/storage/'.$dir,0700,true); $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();$db=DB::connection();$identity=CompositionSchema::identity(); $files=['app/Shared/Installation/CompositionSchema.php','app/Shared/Installation/CompositionSchemaConnection.php','app/Shared/Installation/CompositionSchemaBuilder.php','app/Shared/Installation/CompositionRuntime.php','app/Modules/Services/ServiceCalculation.php','app/Shared/Testing/TestingDatabaseGuard.php','app/Providers/AppServiceProvider.php','config/sgf_single_installation.php']; foreach(CompositionSchema::MIGRATIONS as $file)$files[]='database/migrations/'.$file; foreach(glob($repo.'/database/sql/*.sql') as $file)$files[]='database/sql/'.basename($file); $pins=[];foreach($files as $file)$pins[$file]=hash_file('sha256',$repo.'/'.$file); $schema=new CompositionSchema;$plan=['book'=>$book,'composition'=>$tag,'mode'=>$mode,'source_hash'=>$schema->fingerprint(),'files'=>$pins,'new_access'=>false,'new_business_operations'=>false,'connector_required'=>false,'runtime_enabled'=>false]; file_put_contents($private.'/plan.json',json_encode($plan,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)); if($mode==='--plan'){echo json_encode(['plan'=>$private.'/plan.json','files'=>count($files),'database_writes'=>0]).PHP_EOL;exit;} if($mode==='--verify'){ $stored=$db->getSchemaBuilder()->hasTable('sgf_composition_schema')?$db->table('sgf_composition_schema')->where('id',1)->value('source_hash'):null; $copy=true;foreach($pins as $file=>$pin)if(!is_file($s['app'].'/'.$file)||!hash_equals($pin,hash_file('sha256',$s['app'].'/'.$file)))$copy=false; $valid=is_string($stored)&&hash_equals($schema->fingerprint(),$stored)&&$copy; echo json_encode(['passed'=>$valid,'composition'=>$tag,'code_matches'=>$copy,'database_writes'=>0,'runtime_enabled'=>false]).PHP_EOL;exit($valid?0:2); } // Snapshot pre-existing records and sequences, including every permission and association. $tables=array_column($db->select("SELECT tablename FROM pg_tables WHERE schemaname='public' ORDER BY tablename"),'tablename'); $functionsBefore=array_column($db->select("SELECT oid FROM pg_proc WHERE pronamespace='public'::regnamespace"),'oid'); $sequencesBefore=array_column($db->select("SELECT sequencename FROM pg_sequences WHERE schemaname='public'"),'sequencename'); $snapshot=function()use($db,$tables){$out=[];foreach($tables as $table){if(!preg_match('/^[a-z_][a-z0-9_]*$/D',$table))throw new LogicException('Table');$out[$table]=(array)$db->selectOne('SELECT count(*) rows,md5(coalesce(string_agg(row_to_json(t)::text,chr(10) ORDER BY row_to_json(t)::text),\'\')) hash FROM "'.$table.'" t');}$seq=$db->select("SELECT sequencename,last_value FROM pg_sequences WHERE schemaname='public' AND sequencename=ANY(?::text[]) ORDER BY sequencename",['{'.implode(',',array_column($db->select("SELECT sequencename FROM pg_sequences WHERE schemaname='public'"),'sequencename')).'}']);return ['tables'=>$out,'sequences'=>$seq];}; $before=$snapshot();file_put_contents($private.'/before.json',json_encode($before,JSON_THROW_ON_ERROR)); $process=new Process(['C:/Program Files/PostgreSQL/17/bin/pg_dump.exe','-h','127.0.0.1','-p','55439','-U',$s['env']['DB_USERNAME'],'-d',$s['env']['DB_DATABASE'],'--format=custom','--no-owner','--no-privileges','--file',$private.'/host-before.dump'],$repo,['PGPASSWORD'=>$s['env']['DB_PASSWORD']]);$process->setTimeout(120);$process->mustRun(); $original=[];foreach($files as $file){$dest=$s['app'].'/'.$file;$original[$file]=is_file($dest)?hash_file('sha256',$dest):null;if(is_file($dest)){$backup=$private.'/code-before/'.$file;if(!is_dir(dirname($backup)))mkdir(dirname($backup),0700,true);copy($dest,$backup);}} $copied=[]; try{ $result=$schema->run(true,function($connection)use($files,$pins,$original,$repo,$s,&$copied,$functionsBefore,$tables,$sequencesBefore){ // New PostgreSQL functions otherwise inherit implicit PUBLIC EXECUTE. // Remove only defaults on NEW objects; existing ACLs remain untouched. $restricted=0; foreach($connection->select("SELECT oid,oid::regprocedure::text signature FROM pg_proc WHERE pronamespace='public'::regnamespace") as $fn)if(!in_array($fn->oid,$functionsBefore,true)){$connection->statement('REVOKE ALL ON FUNCTION '.$fn->signature.' FROM PUBLIC');$restricted++;} foreach($connection->select("SELECT tablename FROM pg_tables WHERE schemaname='public'") as $row)if(!in_array($row->tablename,$tables,true))$connection->statement('REVOKE ALL ON TABLE public.'.'"'.str_replace('"','""',$row->tablename).'" FROM PUBLIC'); foreach($connection->select("SELECT sequencename FROM pg_sequences WHERE schemaname='public'") as $row)if(!in_array($row->sequencename,$sequencesBefore,true))$connection->statement('REVOKE ALL ON SEQUENCE public.'.'"'.str_replace('"','""',$row->sequencename).'" FROM PUBLIC'); foreach($files as $file){$dest=$s['app'].'/'.$file;$now=is_file($dest)?hash_file('sha256',$dest):null;if($now!==$original[$file])throw new LogicException('Concurrent code modification; preserve it');if(!is_dir(dirname($dest)))mkdir(dirname($dest),0700,true);if(!copy($repo.'/'.$file,$dest)||!hash_equals($pins[$file],hash_file('sha256',$dest)))throw new RuntimeException('Code copy incomplete');$copied[]=$file;} return ['copied_files'=>count($copied),'new_grants'=>0,'new_documents'=>0,'new_function_public_defaults_removed'=>$restricted,'runtime_enabled'=>false]; }); }catch(Throwable $e){ foreach(array_reverse($copied) as $file){$dest=$s['app'].'/'.$file;if(!is_file($dest)||!hash_equals($pins[$file],hash_file('sha256',$dest)))continue;if($original[$file]===null)unlink($dest);else copy($private.'/code-before/'.$file,$dest);} file_put_contents($private.'/failure.json',json_encode(['failed'=>true,'type'=>$e::class,'database_rollback_requested'=>true,'code_recovery_attempted'=>true]));throw $e; } $after=$snapshot();$preserved=$before['tables']===$after['tables']; // Restrict sequence comparison to the original names; newly installed sequences are expected. $oldSeq=[];foreach($before['sequences'] as $row)$oldSeq[$row->sequencename]=$row->last_value;$newSeq=[];foreach($after['sequences'] as $row)if(array_key_exists($row->sequencename,$oldSeq))$newSeq[$row->sequencename]=$row->last_value;$preserved=$preserved&&$oldSeq===$newSeq; file_put_contents($private.'/after.json',json_encode($after,JSON_THROW_ON_ERROR)); $result=['passed'=>$preserved,'composition'=>$tag,'schema'=>$result,'previous_rows_sequences_permissions_associations_preserved'=>$preserved,'code_files'=>count($files),'runtime_enabled'=>false,'business_operations'=>0,'cache_touched'=>false,'connector_required'=>false,'backup_sha256'=>hash_file('sha256',$private.'/host-before.dump')]; file_put_contents($private.'/result.json',json_encode($result,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo json_encode(['passed'=>$preserved,'composition'=>$tag,'new_tables'=>count($result['schema']['new_tables']??[]),'new_grants'=>0,'runtime_enabled'=>false,'proof'=>$private.'/result.json']).PHP_EOL;exit($preserved?0:2);