This commit is contained in:
2026-11-02 20:27:11 +02:00
parent b44378b899
commit badaada043
300 changed files with 17458 additions and 1056 deletions
+145
View File
@@ -0,0 +1,145 @@
<?php
require dirname(__DIR__).'/integrations/sgf/operational/CodeDeployment.php';
require dirname(__DIR__).'/integrations/sgf/access/AccessOverlay.php';
require dirname(__DIR__).'/integrations/sgf/operational/BudgetOverlay.php';
require dirname(__DIR__).'/integrations/sgf/operational/BootOverlay.php';
use Tempo\Purchasing\Delivery\CodeDeployment;
$root = dirname(__DIR__);
$host = realpath($root.'/../sgf-tempo');
$pointer = file_get_contents($host.'/packages/purchasing/current.json');
$checks = [];
$check = function (bool $ok, string $name) use (&$checks) {
if (! $ok) {
throw new RuntimeException($name);
}$checks[] = $name;
};
$deny = function (callable $work, string $text) use ($check) {
try {
$work();
throw new LogicException('Unexpected success');
} catch (RuntimeException $error) {
$check(str_contains($error->getMessage(), $text), $text);
}
};
$command = escapeshellarg(PHP_BINARY).' '.escapeshellarg($root.'/scripts/prepare-sgf-operational.php').' '.escapeshellarg($host);
exec($command, $output, $exit);
if ($exit !== 0) {
throw new RuntimeException('Prepare failed');
}
$bundle = json_decode(implode("\n", $output), true, 16, JSON_THROW_ON_ERROR)['directory'];
$manifest = json_decode(file_get_contents($bundle.'/manifest.json'), true, 32, JSON_THROW_ON_ERROR);
$hash = hash_file('sha256', $bundle.'/manifest.json');
$make = function () use ($host, $manifest) {
$copy = sys_get_temp_dir().'/sgf-code-deploy-'.bin2hex(random_bytes(6));
mkdir($copy, 0700);
foreach ($manifest['host_overlays'] as $file => $values) {
if (! is_dir(dirname($copy.'/'.$file))) {
mkdir(dirname($copy.'/'.$file), 0700, true);
}copy($host.'/'.$file, $copy.'/'.$file);
}
mkdir($copy.'/packages/purchasing', 0700, true);
copy($host.'/packages/purchasing/current.json', $copy.'/packages/purchasing/current.json');
mkdir($copy.'/bootstrap/cache', 0700, true);
mkdir($copy.'/storage/framework', 0700, true);
file_put_contents($copy.'/bootstrap/cache/config.php', "<?php return ['synthetic'=>true];");
file_put_contents($copy.'/bootstrap/cache/routes-v7.php', '<?php return [];');
file_put_contents($copy.'/bootstrap/cache/unrelated.php', '<?php // preserve unrelated cache support');
return $copy;
};
$copy = $make();
$deploy = new CodeDeployment($copy);
$deny(fn () => new CodeDeployment(''), 'Host explícito obrigatório');
$deny(fn () => $deploy->plan('', $hash), 'Bundle explícito obrigatório');
$plan = $deploy->plan($bundle, $hash);
$check(! $plan['writes'] && ! is_dir($copy.'/storage/app'), 'plan is read-only');
$deny(fn () => $deploy->plan($bundle, str_repeat('0', 64)), 'Manifesto divergente');
file_put_contents($copy.'/.env', 'APP_CONFIG_CACHE=storage/framework/custom.php');
$deny(fn () => $deploy->plan($bundle, $hash), 'Cache Laravel personalizado');
unlink($copy.'/.env');
$deny(fn () => $deploy->apply($bundle, $hash, $plan['target_sha256'], 'Synthetic operator', true), 'manutenção activa');
file_put_contents($copy.'/storage/framework/down', '{"status":503}');
$deny(fn () => $deploy->apply($bundle, $hash, $plan['target_sha256'], 'Synthetic operator', false), 'serviços de escrita parados');
$deny(fn () => $deploy->apply($bundle, $hash, str_repeat('0', 64), 'Synthetic operator', true), 'Destino de código divergente');
$beforeCache = file_get_contents($copy.'/bootstrap/cache/config.php');
$result = $deploy->apply($bundle, $hash, $plan['target_sha256'], 'Synthetic operator', true);
$id = $result['deployment_id'];
$check($result['state'] === 'applied' && ! $result['activation_performed'] && is_file($copy.'/storage/framework/down'), 'applied offline without activation');
$check(! is_file($copy.'/bootstrap/cache/config.php') && ! is_file($copy.'/bootstrap/cache/routes-v7.php') && is_file($copy.'/bootstrap/cache/unrelated.php'), 'invalidates known Laravel caches without touching unrelated files');
foreach ($manifest['host_overlays'] as $file => $values) {
$check(hash_file('sha256', $copy.'/'.$file) === $values['after_sha256'], 'applied verified overlay '.$file);
}
$check($deploy->apply($bundle, $hash, $plan['target_sha256'], 'Synthetic operator', true)['replayed'], 'apply retry does not duplicate installation');
$file = array_key_first($manifest['host_overlays']);
$applied = file_get_contents($copy.'/'.$file);
file_put_contents($copy.'/'.$file, $applied."\n// local change\n");
$deny(fn () => $deploy->rollback($id, 'Synthetic operator', true), 'Código local alterado');
$check(is_dir($copy.'/packages/internal-requisitions'), 'refused rollback preserves bundle and local code');
file_put_contents($copy.'/'.$file, $applied);
file_put_contents($copy.'/bootstrap/cache/config.php', '<?php return ["new_configuration"=>true];');
$deny(fn () => $deploy->rollback($id, 'Synthetic operator', true), 'Cache recriado');
unlink($copy.'/bootstrap/cache/config.php');
$rollback = $deploy->rollback($id, 'Synthetic operator', true);
$check($rollback['state'] === 'rolled-back' && ! $rollback['data_schema_changed'] && is_file($copy.'/storage/framework/down'), 'rollback preserves maintenance and never touches data schema');
$check(file_get_contents($copy.'/bootstrap/cache/config.php') === $beforeCache, 'rollback restores exact previous cache');
foreach ($manifest['host_overlays'] as $file => $values) {
$check(hash_file('sha256', $copy.'/'.$file) === $values['before_sha256'], 'restored original overlay '.$file);
}
$check(! is_dir($copy.'/packages/internal-requisitions') && is_dir($copy.'/storage/app/private/module-deployments/'.$id.'/withdrawn'), 'withdrawn bundle preserved for diagnosis');
$check(file_get_contents($copy.'/packages/purchasing/current.json') === $pointer, 'clone remains on original package pointer');
$failed = $make();
file_put_contents($failed.'/storage/framework/down', '{"status":503}');
$recover = new CodeDeployment($failed);
$plan2 = $recover->plan($bundle, $hash);
$deny(fn () => $recover->apply($bundle, $hash, $plan2['target_sha256'], 'Synthetic failure', true, function ($step) {
if (str_starts_with($step, 'file:')) {
throw new RuntimeException('Injected deployment interruption');
}
}), 'Injected deployment interruption');
$check(is_file($failed.'/storage/framework/down'), 'interruption retains maintenance');
$recover->rollback($id, 'Synthetic recovery', true);
foreach ($manifest['host_overlays'] as $file => $values) {
$check(hash_file('sha256', $failed.'/'.$file) === $values['before_sha256'], 'interrupted deployment recovers '.$file);
}
$check(file_get_contents($host.'/packages/purchasing/current.json') === $pointer, 'destination pointer untouched');
$switched = $make();
file_put_contents($switched.'/storage/framework/down', '{"status":503}');
$switchDeployment = new CodeDeployment($switched);
$switchPlan = $switchDeployment->plan($bundle, $hash);
$deny(fn () => $switchDeployment->apply($bundle, $hash, $switchPlan['target_sha256'], 'Synthetic commit failure', true, function ($step) {
if ($step === 'bundle-switched') {
throw new RuntimeException('Injected post-switch interruption');
}
}), 'Injected post-switch interruption');
$switchDeployment->rollback($id, 'Synthetic post-switch recovery', true);
$check(! is_dir($switched.'/packages/internal-requisitions') && is_file($switched.'/storage/framework/down'), 'post-switch interruption recovers without exposing partial code');
$lockPath = $switched.'/storage/app/private/module-deployments/deployment.lock';
$lock = fopen($lockPath, 'c+');
flock($lock, LOCK_EX);
$deny(fn () => $switchDeployment->rollback($id, 'Synthetic concurrent recovery', true), 'Outra implantação em curso');
flock($lock, LOCK_UN);
fclose($lock);
$cliCopy = $make();
file_put_contents($cliCopy.'/storage/framework/down', '{"status":503}');
$cli = function (array $args) use ($bundle) {
$command = implode(' ', array_map('escapeshellarg', [PHP_BINARY, $bundle.'/scripts/sgf-code-deploy.php', ...$args]));
$rows = [];
exec($command, $rows, $exit);
if ($exit !== 0) {
throw new RuntimeException('Code deployment CLI failed.');
}
return json_decode(implode("\n", $rows), true, 32, JSON_THROW_ON_ERROR);
};
$cliPlan = $cli(['plan', $cliCopy, $bundle, $hash]);
$check(! $cliPlan['writes'], 'CLI plan verifies bundle without writes');
$cliApplied = $cli(['apply', $cliCopy, $bundle, $hash, $cliPlan['target_sha256'], 'Synthetic CLI operator', '--offline']);
$check($cliApplied['state'] === 'applied' && $cliApplied['maintenance_preserved'], 'CLI apply leaves services and maintenance under operator control');
$cliRolled = $cli(['rollback', $cliCopy, $cliApplied['deployment_id'], 'Synthetic CLI recovery', '--offline']);
$check($cliRolled['state'] === 'rolled-back' && file_get_contents($cliCopy.'/packages/purchasing/current.json') === $pointer, 'CLI rollback preserves 0.1.1 pointer');
$proof = ['passed' => true, 'checks' => $checks, 'candidate' => $bundle, 'clones' => [$copy, $failed, $switched, $cliCopy], 'checked_at' => gmdate('c'), 'destination_version' => '0.1.1', 'destination_applied' => false, 'old_suites_repeated' => false, 'database_opened' => false, 'services_restarted' => false];
file_put_contents($root.'/docs/proofs/sgf-code-deploy-delivery.json', json_encode($proof, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
echo json_encode($proof, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)."\n";