"""Restore a verified destination snapshot into a new, guarded QA target only.""" from pathlib import Path import json, datetime, subprocess, os, re, shutil, hashlib R=Path(__file__).resolve().parent.parent; D=R/'storage/app/private/investmoz-v2/portal-audit' read=lambda p: json.loads(Path(p).read_text(encoding='utf-8-sig')) sha=lambda p: hashlib.sha256(Path(p).read_bytes()).hexdigest() old=read(D/'functional-scope-target-backup-20261011.json'); base=read(D/'portal-stability-latest.json') assert old['restore_verified'] and old['files_verified'] and len(old['tables'])==288 assert sha(old['dump_path'])==old['dump_sha256'] and sha(old['files_path'])==old['files_sha256'] stamp=datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%d_%H%M%S') db='workflow_upgrade_'+stamp+'_test'; source=D/('workflow-upgrade-source-'+stamp) assert re.fullmatch(r'workflow_upgrade_\d{8}_\d{6}_test',db) and not source.exists() pg=Path('C:/Program Files/PostgreSQL/17/bin'); env=dict(os.environ,PGPASSWORD='') def run(args): r=subprocess.run([str(a) for a in args],env=env,capture_output=True,text=True,timeout=300) assert r.returncode==0, 'Isolated restore failed; no active operation' return r.stdout.strip() assert run([pg/'psql.exe','-h','127.0.0.1','-p','55441','-U','postgres','-d','postgres','-Atc','SELECT inet_server_port()'])=='55441' run([pg/'createdb.exe','-h','127.0.0.1','-p','55441','-U','postgres',db]) run([pg/'pg_restore.exe','-h','127.0.0.1','-p','55441','-U','postgres','-d',db,'--exit-on-error','--no-owner','--no-privileges',old['dump_path']]) source.mkdir(); original=Path(base['source']) for folder in ['app','config','routes','database','resources','public']: shutil.copytree(original/folder,source/folder,ignore=shutil.ignore_patterns('build-qa-*','*.bin')) (source/'bootstrap/cache').mkdir(parents=True) for file in ['bootstrap/app.php','bootstrap/providers.php','qa-autoload.php','composer.json','composer.lock','package.json','package-lock.json','vite.config.ts']: shutil.copyfile(original/file,source/file) for folder in ['storage/app/private','storage/framework/cache/data','storage/framework/sessions','storage/framework/views','storage/logs','tools']: (source/folder).mkdir(parents=True,exist_ok=True) archive=Path(old['dump_path']).parent shutil.copytree(archive/'files-restored/private',source/'storage/app/private',dirs_exist_ok=True) runtime=read(archive/'effective-runtime.json') text=(archive/'files-restored/runtime/.env').read_text(encoding='utf-8-sig') values={'APP_ENV':'testing','APP_DEBUG':'false','APP_URL':'https://portal-investidor.test:18446', 'APP_KEY':runtime['app_key'],'APP_PREVIOUS_KEYS':','.join(runtime['previous_keys']),'APP_CIPHER':runtime['cipher'], 'DB_CONNECTION':'pgsql','DB_HOST':'127.0.0.1','DB_PORT':'55441','DB_DATABASE':db,'DB_USERNAME':'postgres','DB_PASSWORD':'','DB_URL':'', 'SESSION_COOKIE':'investmoz_workflow_upgrade_'+stamp+'_qa','SESSION_DOMAIN':'null','SESSION_PATH':'/','SESSION_SECURE_COOKIE':'true','SESSION_SAME_SITE':'lax', 'CACHE_STORE':'database','QUEUE_CONNECTION':'database','MAIL_MAILER':'log', 'PORTAL_MANAGER_EMAILS':'workflow-installer-qa@example.invalid,workflow-first-qa@example.invalid,workflow-second-qa@example.invalid', 'PORTAL_NOTIFICATIONS_ENABLED':'false','PORTAL_ORGANIZATION_COUNTRY_ENABLED':'true','PORTAL_PROFILE_ACCESS_ENABLED':'false', 'PORTAL_OPPORTUNITY_DASHBOARD_ACCESS_ENABLED':'false','PORTAL_OPPORTUNITY_SPECIALIZED_DRAFTS_ENABLED':'false', 'PORTAL_OPPORTUNITY_MODULAR_PROFILES_QA_ENABLED':'false','PORTAL_LEGACY_CONTENT_QA_ENABLED':'false','INVESTOR_PATH_ENABLED':'false', 'MALWARE_CLAMD_PORT':'13310','INERTIA_SSR_ENABLED':'false'} for k,v in values.items(): assert len(re.findall('^'+k+'=',text,re.M))<=1 text=re.sub('^'+k+'=.*$',lambda _:k+'='+v,text,flags=re.M) if re.search('^'+k+'=',text,re.M) else text+'\n'+k+'='+v+'\n' (source/'.env').write_text(text,encoding='utf-8') subprocess.run(['powershell','-NoProfile','-Command',f"New-Item -ItemType Junction -Path '{source}/vendor' -Target '{R}/vendor' | Out-Null"],check=True,capture_output=True) runtimephp='''$v){if($v!==null){putenv($n.'='.$v);$_ENV[$n]=$_SERVER[$n]=$v;}} $app=require $root.'/bootstrap/app.php'; (new Illuminate\\Foundation\\Bootstrap\\LoadEnvironmentVariables)->bootstrap($app); (new Illuminate\\Foundation\\Bootstrap\\LoadConfiguration)->bootstrap($app); $c=config('database.connections.'.config('database.default')); throw_unless($c['driver']==='pgsql'&&empty($c['url'])&&$c['host']==='127.0.0.1'&&(int)$c['port']===55441&&$c['database']===$settings['target']['database']&&preg_match('/^workflow_upgrade_\\d{8}_\\d{6}_test$/D',$c['database'])&&!$app->configurationIsCached(),RuntimeException::class,'Exact isolated upgrade target required before providers'); $pdo=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$c['database'],$c['username'],$c['password']);$pdo->exec('BEGIN READ ONLY'); throw_unless($pdo->query('SELECT current_database()')->fetchColumn()===$c['database']&&(int)$pdo->query('SELECT inet_server_port()')->fetchColumn()===55441,RuntimeException::class,'Actual isolated target required');$pdo->exec('ROLLBACK'); $app->make(Illuminate\\Contracts\\Console\\Kernel::class)->bootstrap(); config(['inertia.ssr.enabled'=>false,'suitecrm.enabled'=>false,'investmoz_ai.enabled'=>false]);return $app; ''' (source/'tools/upgrade-runtime.php').write_text(runtimephp,encoding='utf-8') index=(original/'public/index.php').read_text(encoding='utf-8').replace('../tools/portal-stability-runtime.php','../tools/upgrade-runtime.php') (source/'public/index.php').write_text(index,encoding='utf-8') conf=Path(base['compatible_apache_conf']).read_text(encoding='utf-8') # Keep modules, PHP INI, production TLS and binary exactly as the compatible QA; give this server its own listeners/files. pre=conf[:conf.index('')+len('')] # HTTP block https=re.search(r'[\s\S]*?',conf).group() vhost=vhost.replace(':18106',':18108').replace(':18444',':18446');https=https.replace(':18445',':18446').replace(original.as_posix(),source.as_posix()) (qa/'httpd.conf').write_text(pre+vhost+'\n'+https+'\n',encoding='utf-8') plan={'source':str(source),'target':{'database':db,'port':55441},'base':'https://portal-investidor.test:18446','http_base':'http://portal-investidor.test:18108', 'backup_proof':str(D/'functional-scope-target-backup-20261011.json'),'snapshot_directory':str(archive), 'apache_executable':base['compatible_apache_executable'],'apache_conf':str(qa/'httpd.conf'),'created_at':datetime.datetime.now(datetime.timezone.utc).isoformat(), 'active_writes':0,'legacy_source':base['source']} (source/'upgrade-qa.json').write_text(json.dumps(plan,indent=2),encoding='utf-8');(D/'workflow-upgrade-latest.json').write_text(json.dumps(plan,indent=2),encoding='utf-8') print(json.dumps({'result':'isolated_clone_prepared','target':plan['target'],'base':plan['base'],'tables_expected':288,'COUNTRY02_preserved':True,'active_writes':0}))