fix(admin): route multi-megabyte sets to SFTP before shell escaping
deploy-preland / deploy zoomstage.online (push) Successful in 1m3s

This commit is contained in:
Panfilov Konstantin committed 2026-10-25 22:14:15 +03:00
1 parent 6ec813bc99
commit 4fc4fd8162
2 files changed
+27 -3

No files matched your search

+20
View File
@@ -70,6 +70,26 @@ namespace {
SSH2::$withoutZlib=true;
try{$transport->test();throw new RuntimeException('missing zlib accepted');}catch(Problem $error){ensure(str_contains($error->getMessage(),'zlib'),'missing gzinflate returns clear structured error');}
SSH2::$withoutZlib=false;
// Настоящие 90 изображений: два слоя base64 дают аргумент заметно больше PHP shell-limit 2 MiB.
$sourceSet=dirname(__DIR__,2).'/1';$files=[];
foreach(array_keys(\PrelandAdmin\IndpicSetStorage::expectedDimensions()) as $filename){$bytes=file_get_contents($sourceSet.'/'.$filename);$files[$filename]=['data'=>base64_encode($bytes),'sha256'=>hash('sha256',$bytes)];}
$hugePayload=['op'=>'set-write','number'=>3,'files'=>$files,'expected_manifest'=>null];
ensure(count($files)===90&&strlen(base64_encode(json_encode($hugePayload,JSON_THROW_ON_ERROR)))>2097152,'real 90-image set-write payload exceeds native 2 MiB shell argument limit');
$uploadsBeforeHuge=count(SFTP::$uploads);$configBeforeHuge=$transport->readConfig();
$transport->call($hugePayload);
ensure(\PrelandAdmin\Remote::manifest($site.'/3')===\PrelandAdmin\Remote::manifest($sourceSet),'multi-MiB set-write activates all 90 real files with exact hashes');
ensure(count(SFTP::$uploads)===$uploadsBeforeHuge+1,'multi-MiB set-write uses exactly one SFTP inbox');
$hugeInbox=SFTP::$uploads[array_key_last(SFTP::$uploads)];
ensure(!file_exists($hugeInbox),'multi-MiB set-write inbox removed after actual RPC');
ensure(max(array_map('strlen',SSH2::$commands))<=7000,'multi-MiB set-write final exec stays below bootstrap limit');
ensure($transport->readConfig()['version']===$configBeforeHuge['version'],'image upload preserves config and the 2 MiB config contract');
// Обрыв до исполнения большой команды не должен трогать опубликованный набор; inbox удаляется.
$hugePayload['expected_manifest']=\PrelandAdmin\Remote::manifest($site.'/3');$keptManifest=$hugePayload['expected_manifest'];SSH2::$dropInbox=true;
try{$transport->call($hugePayload);throw new RuntimeException('dropped multi-MiB set-write accepted');}
catch(Problem $error){ensure($error->status===504,'interrupted multi-MiB set-write remains unknown, not false success');}
finally{SSH2::$dropInbox=false;}
ensure(\PrelandAdmin\Remote::manifest($site.'/3')===$keptManifest,'interrupted multi-MiB exec preserves previously active set');
ensure(!file_exists(SFTP::$uploads[array_key_last(SFTP::$uploads)]),'interrupted multi-MiB set-write cleans private inbox');
} finally {
$iterator=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixture,FilesystemIterator::SKIP_DOTS),RecursiveIteratorIterator::CHILD_FIRST);
foreach($iterator as $file)$file->isDir()?rmdir($file->getPathname()):unlink($file->getPathname());rmdir($fixture);