111 lines
7.0 KiB
Python
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}))
|