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
+11
-4
@@ -2,6 +2,7 @@
|
||||
/** preland#11: проверенный состав ресурсов; исполняется до SFTP. */
|
||||
declare(strict_types=1);
|
||||
require_once __DIR__ . '/brand-contract.php';
|
||||
require_once __DIR__ . '/check-runtime-sets.php';
|
||||
|
||||
function releaseAssetBytes(string $path, string $bytes): string
|
||||
{
|
||||
@@ -32,7 +33,8 @@ function releaseStaticFiles(string $root): array
|
||||
function validateReleaseAssets(string $root): array
|
||||
{
|
||||
$manifest = json_decode((string) file_get_contents($root . '/release/assets.json'), true, 512, JSON_THROW_ON_ERROR);
|
||||
$files = $manifest['files'] ?? [];
|
||||
// Исторические /N/ записи manifest — только архивный снимок, не runtime guard.
|
||||
$files = array_filter($manifest['files'] ?? [], static fn(string $path): bool => !preg_match('~^[0-9]+/~', $path), ARRAY_FILTER_USE_KEY);
|
||||
$brands = json_decode(file_get_contents($root . '/release/brands.json'), true, 512, JSON_THROW_ON_ERROR);
|
||||
foreach (array_keys($brands) as $domain) prelandBrand($root, $domain);
|
||||
$required = ['docs/logo.svg', 'docs/logo-alt.svg', 'docs/privacy_policy.pdf', 'docs/public_offer.pdf', 'docs/tariffs.pdf', 'docs/user_agreement.pdf'];
|
||||
@@ -40,7 +42,8 @@ function validateReleaseAssets(string $root): array
|
||||
if (!isset($files[$path])) throw new RuntimeException('В manifest отсутствует обязательный ресурс ' . $path);
|
||||
}
|
||||
$names = array_keys($files); sort($names, SORT_STRING);
|
||||
if ($names !== releaseStaticFiles($root)) throw new RuntimeException('Состав статических ресурсов отличается от manifest; синхронизируйте актуальный набор');
|
||||
$static = array_values(array_filter(releaseStaticFiles($root), static fn(string $path): bool => !preg_match('~^[0-9]+/~', $path)));
|
||||
if ($names !== $static) throw new RuntimeException('Состав статических ресурсов отличается от manifest; синхронизируйте актуальный набор');
|
||||
foreach ($files as $path => $record) {
|
||||
if (!preg_match('~^[A-Za-z0-9._/-]+$~', $path) || str_contains($path, '..')) throw new RuntimeException('Недопустимый путь ресурса');
|
||||
$bytes = releaseAssetBytes($path, (string) file_get_contents($root . '/' . $path));
|
||||
@@ -55,7 +58,9 @@ function validateReleaseAssets(string $root): array
|
||||
|
||||
function releaseFiles(string $root): array
|
||||
{
|
||||
$files = array_values(array_filter(releaseStaticFiles($root), static fn(string $path): bool => !preg_match('~^(?:[0-9]+/|docs/logo(?:-alt)?\.svg$)~', $path)));
|
||||
// Положительный контракт публичных ресурсов: admin/, его state/секреты и /N/ не поставляются.
|
||||
$files = array_values(array_filter(releaseStaticFiles($root), static fn(string $path): bool =>
|
||||
preg_match('~^(?:[^/]+\.css|docs/[^/]+\.pdf|favicon/[^/]+\.(?:ico|png|svg|webmanifest)|fonts/[^/]+\.(?:woff2?|ttf|otf)|images/(?:[A-Za-z0-9._-]+/)*[A-Za-z0-9._-]+\.(?:avif|webp|jpe?g|png|gif|svg))$~D', $path) === 1));
|
||||
foreach (['.htaccess', 'index.php', 'i18n.php', 'template.php'] as $path) $files[] = $path;
|
||||
foreach (['components', 'messages'] as $directory) {
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root . '/' . $directory, FilesystemIterator::SKIP_DOTS));
|
||||
@@ -70,13 +75,15 @@ function releaseFiles(string $root): array
|
||||
function verifyRemoteReleaseAssets(array $files, string $base, bool $setsOnly): void
|
||||
{
|
||||
if (!preg_match('~^https://[A-Za-z0-9.-]+$~', $base)) throw new RuntimeException('Требуется HTTPS origin');
|
||||
verifyRemoteRuntimeSets($base);
|
||||
if ($setsOnly) return;
|
||||
if (!$setsOnly) {
|
||||
$brand = prelandBrand(dirname(__DIR__), (string) parse_url($base, PHP_URL_HOST));
|
||||
foreach ($brand['logos'] as $path => $record) $files[$path]['sha256'] = $record['sha256'];
|
||||
}
|
||||
$count = 0;
|
||||
foreach ($files as $path => $record) {
|
||||
if ($setsOnly && !preg_match('~^[0-9]+/~', $path)) continue;
|
||||
if (preg_match('~^[0-9]+/~', $path)) continue;
|
||||
$context = stream_context_create(['http' => ['timeout' => 30, 'header' => "Cache-Control: no-cache\r\n"], 'ssl' => ['verify_peer' => true, 'verify_peer_name' => true]]);
|
||||
$bytes = @file_get_contents($base . '/' . $path . '?release_sha=' . $record['sha256'], false, $context);
|
||||
if ($bytes === false || hash('sha256', releaseAssetBytes($path, $bytes)) !== $record['sha256']) {
|
||||
|
||||
Reference in new issue
Block a user