fix(databases): chown SSL certs before container replacement (#11352)

This commit is contained in:
Andras Bacsai
2026-08-18 11:55:55 +02:00
committed by GitHub
parent 713ddd84fc
commit d360da3270
5 changed files with 21 additions and 13 deletions
+2 -2
View File
@@ -208,11 +208,11 @@ class StartMariadb
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
$this->commands[] = "echo 'Pulling {$database->image} image.'";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
if ($this->database->enable_ssl) {
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml run --rm --no-deps --user root --entrypoint chown $container_name mysql:mysql /etc/mysql/certs/server.key /etc/mysql/certs/server.crt < /dev/null";
}
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
$this->commands[] = "echo 'Database started.'";
+2 -2
View File
@@ -257,11 +257,11 @@ class StartMongodb
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
$this->commands[] = "echo 'Pulling {$database->image} image.'";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
if ($this->database->enable_ssl) {
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml run --rm --no-deps --user root --entrypoint chown $container_name mongodb:mongodb /etc/mongo/certs/server.pem < /dev/null";
}
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
$this->commands[] = "echo 'Database started.'";
+2 -2
View File
@@ -209,11 +209,11 @@ class StartMysql
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
$this->commands[] = "echo 'Pulling {$database->image} image.'";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
if ($this->database->enable_ssl) {
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml run --rm --no-deps --user root --entrypoint chown $container_name mysql:mysql /etc/mysql/certs/server.key /etc/mysql/certs/server.crt < /dev/null";
}
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
$this->commands[] = "echo 'Database started.'";
+2 -2
View File
@@ -219,11 +219,11 @@ class StartPostgresql
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
$this->commands[] = "echo 'Pulling {$database->image} image.'";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
if ($this->database->enable_ssl) {
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml run --rm --no-deps --user root --entrypoint chown $container_name postgres:postgres /var/lib/postgresql/certs/server.key /var/lib/postgresql/certs/server.crt < /dev/null";
}
$this->commands[] = dockerStopCommand(10, $container_name, $this->database->destination->server).' 2>/dev/null || true';
$this->commands[] = "docker rm -f $container_name 2>/dev/null || true";
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
$this->commands[] = "echo 'Database started.'";
@@ -21,33 +21,41 @@ it('escapeshellarg wraps postgres_user in single quotes for chown command', func
->toContain('chown');
});
it('sets postgres SSL file ownership before starting the database container', function () {
it('sets postgres SSL file ownership before replacing the database container', function () {
$source = file_get_contents(__DIR__.'/../../app/Actions/Database/StartPostgresql.php');
$permissionCommandPosition = strpos($source, '--entrypoint chown');
$stopCommandPosition = strpos($source, 'dockerStopCommand');
$startCommandPosition = strpos($source, 'docker-compose.yml up -d');
expect($permissionCommandPosition)->not->toBeFalse()
->and($stopCommandPosition)->not->toBeFalse()
->and($startCommandPosition)->not->toBeFalse()
->and($permissionCommandPosition)->toBeLessThan($stopCommandPosition)
->and($permissionCommandPosition)->toBeLessThan($startCommandPosition)
->and($source)->toContain('/var/lib/postgresql/certs/server.crt < /dev/null')
->and($source)->toContain('postgres:postgres /var/lib/postgresql/certs/server.key')
->not->toContain('chown {$postgresUser}:{$postgresUser}');
});
it('sets database SSL file ownership before startup', function (string $action, string $owner, string $keyPath) {
it('sets database SSL file ownership before replacing the container', function (string $action, string $owner, string $keyPath, string $lastCertificatePath) {
$source = file_get_contents(__DIR__."/../../app/Actions/Database/{$action}.php");
$permissionCommandPosition = strpos($source, '--entrypoint chown');
$stopCommandPosition = strpos($source, 'dockerStopCommand');
$startCommandPosition = strpos($source, 'docker-compose.yml up -d');
expect($permissionCommandPosition)->not->toBeFalse()
->and($stopCommandPosition)->not->toBeFalse()
->and($startCommandPosition)->not->toBeFalse()
->and($permissionCommandPosition)->toBeLessThan($stopCommandPosition)
->and($permissionCommandPosition)->toBeLessThan($startCommandPosition)
->and($source)->toContain("{$lastCertificatePath} < /dev/null")
->and($source)->toContain("{$owner} {$keyPath}");
})->with([
'mysql' => ['StartMysql', 'mysql:mysql', '/etc/mysql/certs/server.key'],
'mariadb' => ['StartMariadb', 'mysql:mysql', '/etc/mysql/certs/server.key'],
'mongodb' => ['StartMongodb', 'mongodb:mongodb', '/etc/mongo/certs/server.pem'],
'mysql' => ['StartMysql', 'mysql:mysql', '/etc/mysql/certs/server.key', '/etc/mysql/certs/server.crt'],
'mariadb' => ['StartMariadb', 'mysql:mysql', '/etc/mysql/certs/server.key', '/etc/mysql/certs/server.crt'],
'mongodb' => ['StartMongodb', 'mongodb:mongodb', '/etc/mongo/certs/server.pem', '/etc/mongo/certs/server.pem'],
]);
it('advisory PoC postgres_user payload is contained by escapeshellarg in chown command', function () {