Produktiv- und Testtabellen per Prefix trennen
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../app/prefixed-pdo.php';
|
||||
|
||||
$assertSame = static function (string $expected, string $actual, string $message): void {
|
||||
if ($expected !== $actual) {
|
||||
fwrite(STDERR, "FEHLER: {$message}\nErwartet: {$expected}\nTatsächlich: {$actual}\n");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
$assertSame('', app_validate_db_table_prefix(''), 'Ein leerer Prefix muss für die einmalige Datenübernahme erlaubt sein.');
|
||||
$assertSame('test_', app_validate_db_table_prefix('test_'), 'Der Test-Prefix muss gültig sein.');
|
||||
$assertSame('prod_', app_validate_db_table_prefix('prod_'), 'Der Produktions-Prefix muss gültig sein.');
|
||||
|
||||
foreach (['Test_', '1test_', 'test', 'test-'] as $invalidPrefix) {
|
||||
try {
|
||||
app_validate_db_table_prefix($invalidPrefix);
|
||||
fwrite(STDERR, "FEHLER: Ungültiger Prefix {$invalidPrefix} wurde akzeptiert.\n");
|
||||
exit(1);
|
||||
} catch (RuntimeException) {
|
||||
// Erwartet.
|
||||
}
|
||||
}
|
||||
|
||||
$previousAppEnv = getenv('APP_ENV');
|
||||
$previousDbPrefix = getenv('DB_TABLE_PREFIX');
|
||||
putenv('APP_ENV=prod');
|
||||
putenv('DB_TABLE_PREFIX');
|
||||
try {
|
||||
app_db_table_prefix();
|
||||
fwrite(STDERR, "FEHLER: Produktion wurde ohne DB_TABLE_PREFIX akzeptiert.\n");
|
||||
exit(1);
|
||||
} catch (RuntimeException) {
|
||||
// Erwartet: Außerhalb von Dev gilt fail-closed.
|
||||
} finally {
|
||||
$previousAppEnv === false ? putenv('APP_ENV') : putenv('APP_ENV=' . $previousAppEnv);
|
||||
$previousDbPrefix === false ? putenv('DB_TABLE_PREFIX') : putenv('DB_TABLE_PREFIX=' . $previousDbPrefix);
|
||||
}
|
||||
|
||||
$assertSame(
|
||||
'SELECT * FROM test_users JOIN test_tenants ON test_tenants.id = test_users.tenant_id',
|
||||
app_prefix_database_sql('SELECT * FROM users JOIN tenants ON tenants.id = users.tenant_id', 'test_'),
|
||||
'Normale Laufzeit-Abfragen müssen vollständig umgeschrieben werden.'
|
||||
);
|
||||
$assertSame(
|
||||
'SELECT * FROM test_users',
|
||||
app_prefix_database_sql('SELECT * FROM test_users', 'test_'),
|
||||
'Bereits umgeschriebene Tabellennamen dürfen keinen doppelten Prefix erhalten.'
|
||||
);
|
||||
$assertSame(
|
||||
"ALTER TABLE test_users ADD CONSTRAINT test_fk_users_tenant FOREIGN KEY (tenant_id) REFERENCES test_tenants(id)",
|
||||
app_prefix_database_sql(
|
||||
'ALTER TABLE users ADD CONSTRAINT fk_users_tenant FOREIGN KEY (tenant_id) REFERENCES tenants(id)',
|
||||
'test_'
|
||||
),
|
||||
'Tabellen und Fremdschlüssel müssen gemeinsam umgeschrieben werden.'
|
||||
);
|
||||
$assertSame(
|
||||
"WHERE TABLE_NAME = 'test_users' AND CONSTRAINT_NAME = 'test_fk_users_tenant'",
|
||||
app_prefix_database_sql("WHERE TABLE_NAME = 'users' AND CONSTRAINT_NAME = 'fk_users_tenant'", 'test_'),
|
||||
'Dynamische Migrationen müssen auch INFORMATION_SCHEMA-Vergleiche umschreiben.'
|
||||
);
|
||||
|
||||
$migrationFiles = glob(__DIR__ . '/../database/migrations/*.sql') ?: [];
|
||||
if (count($migrationFiles) !== 30) {
|
||||
fwrite(STDERR, 'FEHLER: Erwartet wurden 30 Migrationen, gefunden wurden ' . count($migrationFiles) . ".\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$allMigrationSql = '';
|
||||
foreach ($migrationFiles as $migrationFile) {
|
||||
$contents = file_get_contents($migrationFile);
|
||||
if ($contents === false) {
|
||||
fwrite(STDERR, "FEHLER: Migration {$migrationFile} konnte nicht gelesen werden.\n");
|
||||
exit(1);
|
||||
}
|
||||
$allMigrationSql .= "\n" . $contents;
|
||||
}
|
||||
$prefixedMigrationSql = app_prefix_database_sql($allMigrationSql, 'test_');
|
||||
|
||||
foreach (app_database_table_names() as $table) {
|
||||
$rawPattern = '/(?<![A-Za-z0-9_])' . preg_quote($table, '/') . '(?![A-Za-z0-9_])/i';
|
||||
if (preg_match($rawPattern, $allMigrationSql) === 1 && preg_match($rawPattern, $prefixedMigrationSql) === 1) {
|
||||
fwrite(STDERR, "FEHLER: Tabelle {$table} blieb in den umgeschriebenen Migrationen ohne Prefix.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (preg_match('/(?<![A-Za-z0-9_])fk_[A-Za-z0-9_]+(?![A-Za-z0-9_])/i', $prefixedMigrationSql) === 1) {
|
||||
fwrite(STDERR, "FEHLER: Mindestens ein Fremdschlüssel blieb in den Migrationen ohne Prefix.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "DB-Prefix-Prüfung bestanden: Produktion ist fail-closed; Laufzeit-SQL und alle 30 Migrationen werden getrennt umgeschrieben.\n";
|
||||
Reference in New Issue
Block a user