feat: единая админка runtime-конфигов и indpic (#22)
deploy-preland / deploy zoomstage.online (push) Successful in 1m1s
deploy-preland / deploy zoomstage.online (push) Successful in 1m1s
This commit is contained in:
1 parent
5b6b2d2053
commit
9515c1c62b
52 files changed
+2459
-34
No files matched your search
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
require dirname(__DIR__) . '/bootstrap.php';
|
||||
use PrelandAdmin\Config;
|
||||
use PrelandAdmin\Store;
|
||||
use PrelandAdmin\Transport;
|
||||
use PrelandAdmin\Jobs;
|
||||
function check(bool $value, string $message): void { if (!$value) throw new RuntimeException($message); echo "PASS $message\n"; }
|
||||
$root = sys_get_temp_dir() . '/preland-admin-' . bin2hex(random_bytes(6));
|
||||
mkdir($root, 0700, true); mkdir($root . '/site',0700); mkdir($root . '/state',0700);
|
||||
putenv('ADMIN_STATE_DIR=' . $root . '/state'); putenv('ADMIN_LOCAL_ROOTS=' . $root . '/site');
|
||||
$initial = (object)['host'=>'zoomzilla.ru','requisites'=>['one'],'custom'=>(object)['flag'=>true,'zero'=>0,'empty'=>(object)[]],'utm'=>(object)[]];
|
||||
file_put_contents($root . '/site/config.json', json_encode($initial));
|
||||
$store = new Store($root . '/state');
|
||||
$target = $store->saveTarget(['id'=>'test','name'=>'Тест','domain'=>'test.invalid','environment'=>'stage','type'=>'local','root'=>$root . '/site','enabled'=>true]);
|
||||
$store->verifyTarget('test');$target=$store->target('test');
|
||||
$transport = new Transport($store, $target);
|
||||
$before = $transport->readConfig();
|
||||
$next = Config::patch($before['config'], [['path'=>['host'],'value'=>'example.org']]);
|
||||
check($next->custom->flag === true && $next->custom->zero === 0 && $next->custom->empty instanceof stdClass, 'selected patch preserves unrelated values and types');
|
||||
$transport->writeConfig($before['version'], Config::encode($next));
|
||||
$after = $transport->readConfig(); check($after['config']->host === 'example.org','atomic save and reread');
|
||||
try { $transport->writeConfig($before['version'], Config::encode($initial)); throw new RuntimeException('missed conflict'); } catch (PrelandAdmin\Conflict $e) { check(true,'stale version conflicts'); }
|
||||
check(count($store->backups('test')) === 1,'private backup saved');
|
||||
$jobs = new Jobs($store);
|
||||
$job = $jobs->create('apply', ['targets'=>[['id'=>'test','version'=>$after['version']],['id'=>'missing','version'=>'x']], 'changes'=>[['path'=>['custom','flag'],'value'=>false]]]);
|
||||
$jobs->run($job['id']); $job=$jobs->get($job['id']);
|
||||
check($job['results'][0]['status']==='success' && $job['results'][1]['status']==='error','one target failure does not undo successful target');
|
||||
$restored=$transport->readConfig();
|
||||
$backup=$store->backups('test')[0];
|
||||
$job=$jobs->create('restore',['target'=>'test','id'=>$backup['id'],'version'=>$restored['version']]);$jobs->run($job['id']);
|
||||
check($jobs->get($job['id'])['results'][0]['status']==='success','backup restores with version protection');
|
||||
try { $store->saveTarget(['id'=>'escape','type'=>'local','root'=>'/etc','domain'=>'a.invalid']); throw new RuntimeException('unsafe root accepted'); } catch (PrelandAdmin\Problem $e) {check(true,'local root confined to explicit mounts');}
|
||||
try { Config::patch($initial,[['path'=>['__proto__'],'value'=>1]]); throw new RuntimeException('unsafe key accepted'); } catch(PrelandAdmin\Problem $e) {check(true,'unsafe patch path rejected');}
|
||||
echo "Backend contract complete\n";
|
||||
Reference in new issue
Block a user