Harden permissions for sqlite runtime

This commit is contained in:
root
2026-01-28 18:46:06 +02:00
parent ec120074ec
commit a8d6bbe16e
4 changed files with 83 additions and 1 deletions

View File

@@ -1 +1 @@
VERSION=0.9-rc13 VERSION=0.9-rc14

View File

@@ -90,6 +90,7 @@ class UpgradeCommand extends Command
try { try {
$this->configureGitSafeDirectory(); $this->configureGitSafeDirectory();
$this->ensureGitRepository(); $this->ensureGitRepository();
$this->ensureWritableStorage();
$statusResult = $this->executeCommand('git status --porcelain'); $statusResult = $this->executeCommand('git status --porcelain');
if ($statusResult['exitCode'] !== 0) { if ($statusResult['exitCode'] !== 0) {
throw new Exception($statusResult['output'] ?: 'Unable to read git status.'); throw new Exception($statusResult['output'] ?: 'Unable to read git status.');
@@ -317,6 +318,13 @@ class UpgradeCommand extends Command
} }
} }
protected function ensureWritableStorage(): void
{
foreach ($this->getWritableStorageCommands() as $command) {
$this->executeCommand($command);
}
}
protected function getSafeDirectoryCommands(): array protected function getSafeDirectoryCommands(): array
{ {
$directory = $this->basePath; $directory = $this->basePath;
@@ -337,6 +345,28 @@ class UpgradeCommand extends Command
return $commands; return $commands;
} }
protected function getWritableStorageCommands(): array
{
if (! $this->isRunningAsRoot() || ! $this->userExists('www-data')) {
return [];
}
$paths = [
$this->basePath.'/database',
$this->basePath.'/storage',
$this->basePath.'/bootstrap/cache',
];
$escapedPaths = array_map('escapeshellarg', $paths);
$pathList = implode(' ', $escapedPaths);
return [
"chgrp -R www-data {$pathList}",
"chmod -R g+rwX {$pathList}",
"find {$pathList} -type d -exec chmod g+s {} +",
];
}
protected function commandExists(string $command): bool protected function commandExists(string $command): bool
{ {
$result = $this->executeCommand("command -v {$command}"); $result = $this->executeCommand("command -v {$command}");

View File

@@ -768,6 +768,19 @@ clone_jabali() {
git config --system --add safe.directory "$JABALI_DIR" 2>/dev/null || true git config --system --add safe.directory "$JABALI_DIR" 2>/dev/null || true
sudo -u $JABALI_USER git config --global --add safe.directory "$JABALI_DIR" 2>/dev/null || true sudo -u $JABALI_USER git config --global --add safe.directory "$JABALI_DIR" 2>/dev/null || true
# Ensure runtime directories stay writable for PHP-FPM (default: www-data)
if id www-data &>/dev/null; then
chown -R $JABALI_USER:www-data \
"$JABALI_DIR/database" \
"$JABALI_DIR/storage" \
"$JABALI_DIR/bootstrap/cache" 2>/dev/null || true
chmod -R g+rwX \
"$JABALI_DIR/database" \
"$JABALI_DIR/storage" \
"$JABALI_DIR/bootstrap/cache" 2>/dev/null || true
find "$JABALI_DIR/database" "$JABALI_DIR/storage" "$JABALI_DIR/bootstrap/cache" -type d -exec chmod g+s {} + 2>/dev/null || true
fi
# Read version from cloned VERSION file # Read version from cloned VERSION file
if [[ -f "$JABALI_DIR/VERSION" ]]; then if [[ -f "$JABALI_DIR/VERSION" ]]; then
source "$JABALI_DIR/VERSION" source "$JABALI_DIR/VERSION"

View File

@@ -110,6 +110,40 @@ class UpgradeCommandTest extends TestCase
'sudo -u www-data git config --global --add safe.directory '.base_path(), 'sudo -u www-data git config --global --add safe.directory '.base_path(),
], $command->exposesSafeDirectoryCommands()); ], $command->exposesSafeDirectoryCommands());
} }
public function test_writable_storage_commands_for_non_root(): void
{
$command = new SafeDirectoryUpgradeCommand(false, true, true);
$this->assertSame([], $command->exposesWritableStorageCommands());
}
public function test_writable_storage_commands_without_www_data(): void
{
$command = new SafeDirectoryUpgradeCommand(true, true, false);
$this->assertSame([], $command->exposesWritableStorageCommands());
}
public function test_writable_storage_commands_for_root_with_www_data(): void
{
$command = new SafeDirectoryUpgradeCommand(true, true, true);
$paths = [
base_path().'/database',
base_path().'/storage',
base_path().'/bootstrap/cache',
];
$escaped = array_map('escapeshellarg', $paths);
$list = implode(' ', $escaped);
$this->assertSame([
"chgrp -R www-data {$list}",
"chmod -R g+rwX {$list}",
"find {$list} -type d -exec chmod g+s {} +",
], $command->exposesWritableStorageCommands());
}
} }
class TestableUpgradeCommand extends UpgradeCommand class TestableUpgradeCommand extends UpgradeCommand
@@ -145,6 +179,11 @@ class SafeDirectoryUpgradeCommand extends UpgradeCommand
return $this->getSafeDirectoryCommands(); return $this->getSafeDirectoryCommands();
} }
public function exposesWritableStorageCommands(): array
{
return $this->getWritableStorageCommands();
}
protected function isRunningAsRoot(): bool protected function isRunningAsRoot(): bool
{ {
return $this->runningAsRoot; return $this->runningAsRoot;