fix: актуальные ресурсы Zoomzilla и проверяемый выпуск (refs #11)
This commit is contained in:
1 parent
144dda6d88
commit
e9a2a0d568
25 files changed
+1255
-67
No files matched your search
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/** preland#11: старый бренд запрещён независимо от обновления manifest. */
|
||||
declare(strict_types=1);
|
||||
$root = dirname(__DIR__);
|
||||
$oldBlob = '91267982e1ad373b6ebd5fb2b761b34fe2a0c2a5';
|
||||
foreach (['docs/logo.svg', 'docs/logo-alt.svg'] as $file) {
|
||||
$body = str_replace("\r\n", "\n", file_get_contents($root . '/' . $file));
|
||||
if (sha1('blob ' . strlen($body) . chr(0) . $body) === $oldBlob) {
|
||||
fwrite(STDERR, "FAILED: {$file} содержит запрещённую заглушку бренда\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
require $root . '/bin/release-assets.php';
|
||||
validateReleaseAssets($root);
|
||||
$files = releaseFiles($root);
|
||||
foreach (['docs/logo.svg', 'docs/logo-alt.svg', 'docs/privacy_policy.pdf', 'template.php'] as $file) {
|
||||
if (!in_array($file, $files, true)) throw new RuntimeException('Не включён ' . $file);
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if (preg_match('~^(tests/|bin/|release/|docs/superpowers/|config\.json$|[0-9]+/)~', $file)) {
|
||||
throw new RuntimeException('В кодовую поставку попал защищённый/служебный файл ' . $file);
|
||||
}
|
||||
}
|
||||
// Повреждение/удаление ресурса и подмена manifest не должны проходить preflight.
|
||||
$fixture = sys_get_temp_dir() . '/preland11-' . bin2hex(random_bytes(6));
|
||||
mkdir($fixture);
|
||||
$copy = static function (string $relative) use ($root, $fixture): void {
|
||||
$target = $fixture . '/' . $relative;
|
||||
if (!is_dir(dirname($target))) mkdir(dirname($target), 0700, true);
|
||||
copy($root . '/' . $relative, $target);
|
||||
};
|
||||
$manifest = json_decode(file_get_contents($root . '/release/assets.json'), true, 512, JSON_THROW_ON_ERROR);
|
||||
foreach (array_keys($manifest['files']) as $file) $copy($file);
|
||||
$copy('release/assets.json');
|
||||
try {
|
||||
validateReleaseAssets($fixture);
|
||||
$mustFail = static function (callable $mutate) use ($fixture): void {
|
||||
$mutate();
|
||||
try { validateReleaseAssets($fixture); } catch (RuntimeException $e) { return; }
|
||||
throw new RuntimeException('Повреждённый ресурс принят');
|
||||
};
|
||||
$mustFail(fn() => file_put_contents($fixture . '/docs/logo.svg', 'broken'));
|
||||
$copy('docs/logo.svg');
|
||||
$mustFail(fn() => unlink($fixture . '/docs/public_offer.pdf'));
|
||||
$copy('docs/public_offer.pdf');
|
||||
$mustFail(function () use ($fixture, $manifest): void {
|
||||
unset($manifest['files']['docs/logo-alt.svg']);
|
||||
file_put_contents($fixture . '/release/assets.json', json_encode($manifest));
|
||||
});
|
||||
$copy('release/assets.json');
|
||||
$mustFail(function () use ($fixture, $manifest): void {
|
||||
$body = '<svg>WBE70</svg>';
|
||||
file_put_contents($fixture . '/docs/logo.svg', $body);
|
||||
$manifest['files']['docs/logo.svg']['sha256'] = hash('sha256', $body);
|
||||
file_put_contents($fixture . '/release/assets.json', json_encode($manifest));
|
||||
});
|
||||
} finally {
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixture, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST);
|
||||
foreach ($iterator as $item) $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
|
||||
rmdir($fixture);
|
||||
}
|
||||
echo "OK: текущие ресурсы, повреждение/удаление/подмена manifest и состав поставки\n";
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/** preland#11: разрешено менять только согласованный ключ requisites. */
|
||||
declare(strict_types=1);
|
||||
$root = dirname(__DIR__);
|
||||
$expected = json_decode(file_get_contents($root . '/release/requisites.json'), true, 512, JSON_THROW_ON_ERROR);
|
||||
$saved = json_decode(file_get_contents($root . '/config.json'), true, 512, JSON_THROW_ON_ERROR);
|
||||
if (($saved['requisites'] ?? null) !== $expected) {
|
||||
fwrite(STDERR, "FAILED: Git config содержит старые реквизиты\n"); exit(1);
|
||||
}
|
||||
$raw = "{\n \"host\" : \"custom.example\", \"nested\":{\"requisites\":[\"do not change\"]},\n \"requisites\": [\"old\",\"escaped \\\"quote\"], \"utm\" : {\"focus\":\"custom\"}, \"unknown\":\"\\u0041\"\n}\n";
|
||||
$path = tempnam(sys_get_temp_dir(), 'requs-');
|
||||
try {
|
||||
foreach ([$raw, '{"host":"other.example","unknown":{"a":1}}'] as $fixture) {
|
||||
file_put_contents($path, $fixture);
|
||||
exec(PHP_BINARY . ' ' . escapeshellarg($root . '/bin/ensure-requisites-config.php') . ' ' . escapeshellarg($path), $output, $code);
|
||||
if ($code !== 10) throw new RuntimeException('Ожидалась точечная замена requisites');
|
||||
$after = file_get_contents($path);
|
||||
$beforeData = json_decode($fixture, true, 512, JSON_THROW_ON_ERROR);
|
||||
$afterData = json_decode($after, true, 512, JSON_THROW_ON_ERROR);
|
||||
if ($afterData['requisites'] !== $expected) throw new RuntimeException('Реквизиты не заменены');
|
||||
unset($beforeData['requisites'], $afterData['requisites']);
|
||||
if ($beforeData !== $afterData) throw new RuntimeException('Другие значения изменены');
|
||||
if (isset($afterData['nested']) && !str_contains($after, '"unknown":"\\u0041"')) throw new RuntimeException('Изменены байты чужих полей');
|
||||
exec(PHP_BINARY . ' ' . escapeshellarg($root . '/bin/ensure-requisites-config.php') . ' ' . escapeshellarg($path), $output, $code);
|
||||
if ($code !== 0 || file_get_contents($path) !== $after) throw new RuntimeException('Повторная операция не идемпотентна');
|
||||
}
|
||||
} finally { unlink($path); }
|
||||
echo "OK: requisites-only, чужие поля/байты сохранены, повторный запуск без изменений\n";
|
||||
Reference in new issue
Block a user