php \ // /var/www/html/shared/platform-tools/bin/encrypt_secrets.php [--dry-run] // // Idempotent -- rows already carrying the enc:v1: prefix are left alone -- so it // is safe to call from deploy.sh on every deploy. Exits non-zero if a row that // should be encrypted could not be, so a deploy notices. // // Every site opens $pdo in its config/db.php; that is the whole bootstrap. declare(strict_types=1); $repoRoot = dirname(__DIR__, 3); $dryRun = in_array('--dry-run', $argv, true); $pdo = null; if (is_file($repoRoot . '/config/db.php')) { require_once $repoRoot . '/config/db.php'; // defines $pdo if (is_file($repoRoot . '/config/functions.php')) { require_once $repoRoot . '/config/functions.php'; } } if (!$pdo instanceof PDO) { fwrite(STDERR, "encrypt_secrets: could not open a PDO connection for {$repoRoot}\n"); exit(2); } // A bootstrap with a hardcoded fallback schema would connect somewhere // harmless-looking when the environment did not reach it, and "encrypt" // nothing, reporting success. Refuse unless the live connection is the schema // DB_NAME actually names. $expected = (string) ($_ENV['DB_NAME'] ?? getenv('DB_NAME') ?: ''); $actual = (string) $pdo->query('SELECT DATABASE()')->fetchColumn(); if ($expected !== '' && $actual !== $expected) { fwrite(STDERR, "encrypt_secrets: connected to '{$actual}' but DB_NAME is '{$expected}' -- refusing to run.\n"); exit(2); } require_once dirname(__DIR__) . '/functions_settings.php'; if (!platform_settings_secret_available()) { fwrite(STDERR, "encrypt_secrets: no APP_SECRET_KEY (or BACKUP_TOKEN) configured -- refusing to run.\n"); exit(3); } if ($dryRun) { // Report without writing: list secret-named rows still in plaintext. $rows = $pdo->query("SELECT setting_key, setting_value FROM system_settings")->fetchAll(PDO::FETCH_ASSOC); $pending = []; foreach ($rows as $row) { $k = (string) $row['setting_key']; $v = (string) $row['setting_value']; if (platform_settings_is_secret($k) && $v !== '' && !str_starts_with($v, PLATFORM_SECRET_PREFIX)) { $pending[] = $k; } } echo $pending ? "would encrypt: " . implode(', ', $pending) . "\n" : "nothing to encrypt -- all secret rows are empty or already encrypted\n"; exit(0); } $report = platform_settings_encrypt_existing($pdo); foreach ($report['encrypted'] as $k) echo "encrypted: {$k}\n"; foreach ($report['skipped'] as $k) echo "skipped: {$k}\n"; foreach ($report['failed'] as $k) fwrite(STDERR, "FAILED: {$k}\n"); printf( "%d encrypted, %d skipped, %d failed\n", count($report['encrypted']), count($report['skipped']), count($report['failed']) ); exit($report['failed'] ? 1 : 0);