Files
Investidor-V2/tools/portal-service-followup-environment.py
T
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

79 lines
6.7 KiB
Python

"""Independent QA for service limits and cross-confirmed bootstrap; fixed artefacts stay intact."""
from pathlib import Path
import json, datetime, subprocess, os, re, shutil, hashlib
R = Path(__file__).resolve().parent.parent
P = 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(P / 'workflow-upgrade-target-backup-20261011.json')
previous = read(P / 'workflow-upgrade-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 = P / ('workflow-service-followup-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):
result = subprocess.run([str(x) for x in args], env=env, capture_output=True, text=True, timeout=300)
assert result.returncode == 0, 'Isolated preparation failed; no destination operation'
return result.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(previous['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')
manager = re.search(r'^PORTAL_MANAGER_EMAILS=(.*)$',text,re.M)
values = {
'APP_ENV':'testing','APP_DEBUG':'false','APP_URL':'https://portal-investidor.test:18448',
'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_service_followup_'+stamp,'SESSION_DOMAIN':'null','SESSION_PATH':'/','SESSION_SECURE_COOKIE':'true','SESSION_SAME_SITE':'lax',
'CACHE_STORE':'database','QUEUE_CONNECTION':'database','DB_QUEUE':'services-followup-qa','DB_QUEUE_RETRY_AFTER':'210',
'MAIL_MAILER':'log','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',
'CLAMD_PORT':'13310','INERTIA_SSR_ENABLED':'false',
'PORTAL_MANAGER_EMAILS': ((manager.group(1).strip("\"'")+',') if manager else '')+'workflow-first-qa@example.invalid,workflow-second-qa@example.invalid',
}
for key,value in values.items():
assert len(re.findall('^'+key+'=',text,re.M)) <= 1
text = re.sub('^'+key+'=.*$',lambda _:key+'='+value,text,flags=re.M) if re.search('^'+key+'=',text,re.M) else text+'\n'+key+'='+value+'\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)
guard = (original/'tools/upgrade-runtime.php').read_text(encoding='utf-8').replace(':18446',':18448')
(source/'tools/upgrade-runtime.php').write_text(guard,encoding='utf-8')
shutil.copyfile(original/'public/index.php',source/'public/index.php')
conf = Path(previous['apache_conf']).read_text(encoding='utf-8')
conf = conf.replace(original.as_posix(),source.as_posix()).replace(':18446',':18448').replace(':18108',':18110')
conf = conf.replace('ServerName portal-investidor.test:18446','ServerName portal-investidor.test:18448')
https_pos = conf.index('<VirtualHost 127.0.0.1:18448>')
conf = conf[:https_pos] + conf[https_pos:].replace('DocumentRoot ', 'php_admin_value upload_max_filesize 20M\nphp_admin_value post_max_size 24M\nphp_admin_value memory_limit 256M\nphp_admin_value max_execution_time 180\nDocumentRoot ', 1)
(source/'apache-qa').mkdir()
(source/'apache-qa/httpd.conf').write_text(conf,encoding='utf-8')
plan = {**previous,'source':str(source),'target':{'database':db,'port':55441},'base':'https://portal-investidor.test:18448',
'http_base':'http://portal-investidor.test:18110','apache_conf':str(source/'apache-qa/httpd.conf'),
'backup_proof':str(P/'workflow-upgrade-target-backup-20261011.json'),'created_at':datetime.datetime.now(datetime.timezone.utc).isoformat(),
'previous_candidate':'98a8e0b70892','active_writes':0,'queue':'services-followup-qa'}
(source/'upgrade-qa.json').write_text(json.dumps(plan,indent=2),encoding='utf-8')
(P/'service-followup-latest.json').write_text(json.dumps(plan,indent=2),encoding='utf-8')
snapshot = {'candidate':read(R/'outputs/investmoz-workflow-upgrade-20261011/pacote.json'),
'candidate_file_hashes':{p.name:sha(p) for p in (R/'outputs/investmoz-workflow-upgrade-20261011').iterdir() if p.is_file()},
'service_plan_file_hashes':{p.name:sha(p) for p in (R/'outputs/investmoz-workflow-service-plan-20261011').iterdir() if p.is_file()},
'active_hashes':{p:sha(R/p) for p in ['.env','public/build/manifest.json','app/Services/PortalSuperusers.php','app/Services/PortalProfileInstallation.php','app/Http/Controllers/PortalProfileInstallationController.php','routes/web.php','resources/js/pages/profiles/installation.tsx']}}
(P/'service-followup-preservation-before.json').write_text(json.dumps(snapshot,indent=2),encoding='utf-8')
print(json.dumps({'result':'new_isolated_clone_prepared','base':plan['base'],'target':plan['target'],'active_writes':0}))