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

111 lines
7.0 KiB
Python

"""Create standalone Apache QA using the destination PHP/TLS stack, never active includes."""
from pathlib import Path
import json, re, shutil
ROOT=Path(__file__).resolve().parent.parent
PRIVATE=ROOT/'storage/app/private/investmoz-v2/portal-audit'
read=lambda p:json.loads(Path(p).read_text(encoding='utf-8-sig'))
plan=read(PRIVATE/'portal-stability-latest.json'); source=Path(plan['source'])
fresh_link=read(PRIVATE/'country-https-backup-latest.json'); fresh=read(fresh_link['path'])
prior_link=read(PRIVATE/'country-https-backup-before-resume-20261011.json')
assert fresh['restore_verified'] and fresh['files_verified'] and fresh['restored_target']['port']==55441
assert re.fullmatch(r'country_candidate_\d{8}_\d{6}_test',fresh['restored_target']['database'])
env=(Path(fresh_link['directory'])/'files-restored/runtime/.env').read_text(encoding='utf-8-sig')
runtime=read(Path(fresh_link['directory'])/'files-restored/runtime/effective-runtime.json')
values={'APP_ENV':'testing','APP_DEBUG':'false','APP_URL':'https://portal-investidor.test:18443',
'APP_KEY':runtime['app_key'],'APP_PREVIOUS_KEYS':'','APP_CIPHER':runtime['cipher'],
'DB_CONNECTION':'pgsql','DB_HOST':'127.0.0.1','DB_PORT':'55441','DB_DATABASE':fresh['restored_target']['database'],
'DB_USERNAME':'postgres','DB_PASSWORD':'','DB_URL':'',
'SESSION_COOKIE':'investmoz_stability_18443_qa','SESSION_SECURE_COOKIE':'true','SESSION_DOMAIN':'null',
'SESSION_PATH':'/','SESSION_SAME_SITE':'lax','SESSION_DRIVER':fresh['runtime']['session_driver'],
'CACHE_STORE':'database','QUEUE_CONNECTION':'database','MAIL_MAILER':'log',
'PORTAL_MANAGER_EMAILS':'stability-installer@example.invalid','PORTAL_NOTIFICATIONS_ENABLED':'false',
'PORTAL_NOTIFICATION_RECIPIENTS':'','PORTAL_ORGANIZATION_COUNTRY_ENABLED':'false',
'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'}
for name,value in values.items():
assert len(re.findall(r'^'+name+r'=',env,re.M))<=1
line=name+'='+value
env=re.sub(r'^'+name+r'=.*$',lambda _:line,env,flags=re.M) if re.search(r'^'+name+r'=',env,re.M) else env+'\n'+line+'\n'
assert not (source/'.env').exists()
(source/'.env').write_text(env,encoding='utf-8')
(source/'tools').mkdir(exist_ok=True)
shutil.copyfile(ROOT/'tools/portal-stability-runtime.php',source/'tools/portal-stability-runtime.php')
settings={'target':fresh['restored_target'],'backup_proof':fresh_link['path'],'previous_qa_proof':prior_link['path'],
'base':'https://portal-investidor.test:18443','http_base':'http://portal-investidor.test:18105',
'credentials_path':str(source/'storage/app/private/stability-actors.json')}
(source/'stability-qa.json').write_text(json.dumps(settings,indent=2),encoding='utf-8')
for name in ['.htaccess','favicon.svg','favicon.ico','robots.txt','logo.svg']:
if (ROOT/'public'/name).is_file(): shutil.copyfile(ROOT/'public'/name,source/'public'/name)
(source/'public/index.php').write_text('''<?php
define('LARAVEL_START', microtime(true));
/** The isolated target is checked BEFORE any service provider or session can write. */
$app = require __DIR__.'/../tools/portal-stability-runtime.php';
$request = Illuminate\\Http\\Request::capture();
$kernel = $app->make(Illuminate\\Contracts\\Http\\Kernel::class);
$response = $kernel->handle($request);
$response->headers->set('X-Investmoz-QA-Target', config('database.connections.pgsql.database').':55441');
$response->headers->set('X-Investmoz-Candidate-Code', app(App\\Services\\OrganizationCountryInstallation::class)->fingerprint());
if ($request->hasSession()) $response->headers->set('X-Investmoz-QA-Session-Hash', hash('sha256', $request->session()->getId()));
$response->headers->set('X-Investmoz-QA-PHP', PHP_VERSION.'; '.PHP_SAPI);
$response->send();
$kernel->terminate($request,$response);
''',encoding='utf-8')
# No production files are shared except immutable installed dependencies/modules.
documents=Path(fresh_link['directory'])/'files-restored/private'
if documents.is_dir(): shutil.copytree(documents,source/'storage/app/private',dirs_exist_ok=True)
apache=Path('C:/laragon/bin/apache/httpd-2.4.54-win64-VS16')
modules='\n'.join(line for line in (apache/'conf/httpd.conf').read_text().splitlines() if line.startswith('LoadModule '))
php_conf=Path('C:/laragon/etc/apache2/mod_php.conf').read_text()
cert_dir=Path('C:/Users/macbook/.config/investmoz/tls')
assert (cert_dir/'portal-investidor.test-fullchain.pem').is_file() and (cert_dir/'portal-investidor.test-key.pem').is_file()
qa=(source/'apache-qa');qa.mkdir(exist_ok=True)
conf=f'''ServerRoot "{apache.as_posix()}"
PidFile "{(qa/'httpd.pid').as_posix()}"
Listen 127.0.0.1:18443
Listen 127.0.0.1:18105
ServerName portal-investidor.test
{modules}
{php_conf}
ErrorLog "{(qa/'error.log').as_posix()}"
LogLevel warn
DirectoryIndex index.php
SSLSessionCache none
<Directory />
AllowOverride None
Require all denied
</Directory>
<VirtualHost 127.0.0.1:18105>
ServerName portal-investidor.test
RewriteEngine On
RewriteCond %{{REQUEST_METHOD}} !^(GET|HEAD)$
RewriteRule ^ - [R=405,L]
RewriteRule ^ https://portal-investidor.test:18443%{{REQUEST_URI}} [R=308,L,NE]
</VirtualHost>
<VirtualHost 127.0.0.1:18443>
ServerName portal-investidor.test
DocumentRoot "{(source/'public').as_posix()}"
SSLEngine on
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCertificateFile "{(cert_dir/'portal-investidor.test-fullchain.pem').as_posix()}"
SSLCertificateKeyFile "{(cert_dir/'portal-investidor.test-key.pem').as_posix()}"
<Directory "{(source/'public').as_posix()}">
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Header always set X-Content-Type-Options nosniff
</VirtualHost>
'''
(qa/'httpd.conf').write_text(conf,encoding='utf-8')
plan.update({'qa_environment':settings,'apache_conf':str(qa/'httpd.conf'),
'apache_executable':str(apache/'bin/httpd.exe'),'php_ini':'C:/laragon/bin/php/php-8.5.11-Win32-vs17-x64/php.ini',
'unavoidable_differences':['Ports 18443/18105 instead of 443/80; active Apache untouched',
'Database clone on 55441 with synthetic actors and explicit synthetic representation',
'Unique QA session cookie and isolated browser profile; shared hostname cookies cannot distinguish ports',
'Loopback-only access; mail recorded locally; no external notification or decision',
'QA guard/instrumentation checks target before providers; excluded from deployment']})
(PRIVATE/'portal-stability-latest.json').write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8')
print(json.dumps({'result':'isolated_Apache_QA_prepared','origin':settings['base'],'target':settings['target'],
'apache_conf':str(qa/'httpd.conf'),'active_config_modified':False,'active_writes':0}))