diff --git a/deploy/Dockerfile b/deploy/Dockerfile index b5866c0c..a03794b1 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -88,7 +88,9 @@ FROM php-base AS runtime # Keep the existing PHP/Composer cache layers when adding PostgreSQL support. RUN apt-get -o Acquire::Retries=3 update \ - && apt-get -o Acquire::Retries=3 install -y --no-install-recommends libpq-dev \ + && apt-get -o Acquire::Retries=3 install -y --no-install-recommends \ + acl \ + libpq-dev \ && docker-php-ext-install -j2 pdo_pgsql \ && rm -rf /var/lib/apt/lists/* diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh index 422e0dd2..7d86eeb9 100644 --- a/deploy/entrypoint.sh +++ b/deploy/entrypoint.sh @@ -22,8 +22,31 @@ if [ "$(id -u)" = "0" ]; then fi fi +grant_web_process_acl() { + command -v setfacl >/dev/null 2>&1 || return 0 + + for path in \ + storage/framework/cache \ + storage/framework/sessions \ + storage/framework/views \ + storage/logs \ + bootstrap/cache + do + [ -e "$path" ] || continue + setfacl -R -m u:www-data:rwx "$path" + find "$path" -type d -exec \ + setfacl -m d:u:www-data:rwx,d:u::rwx,d:g::rwx,d:m::rwx,d:o::rx {} + + done +} + +if [ "$(id -u)" = "0" ]; then + grant_web_process_acl +fi + assert_web_writable() { runuser -u www-data -- test -w storage/app + runuser -u www-data -- test -w storage/framework/cache/data + runuser -u www-data -- test -w storage/framework/sessions runuser -u www-data -- test -w storage/framework/views runuser -u www-data -- test -w storage/logs runuser -u www-data -- test -w bootstrap/cache @@ -72,4 +95,8 @@ if [ "${1:-}" = "apache2-foreground" ]; then fi fi +if [ "$(id -u)" = "0" ] && [ "${1:-}" != "apache2-foreground" ]; then + exec runuser -u www-data -- "$@" +fi + exec "$@" diff --git a/tests/Unit/Deployment/WebProcessOwnershipTest.php b/tests/Unit/Deployment/WebProcessOwnershipTest.php index 12130d05..273873e4 100644 --- a/tests/Unit/Deployment/WebProcessOwnershipTest.php +++ b/tests/Unit/Deployment/WebProcessOwnershipTest.php @@ -20,9 +20,28 @@ class WebProcessOwnershipTest extends TestCase $entrypoint ); $this->assertStringContainsString('assert_web_writable', $entrypoint); + $this->assertStringContainsString('grant_web_process_acl', $entrypoint); + $this->assertStringContainsString( + 'setfacl -m d:u:www-data:rwx,d:u::rwx,d:g::rwx,d:m::rwx,d:o::rx', + $entrypoint + ); + $this->assertStringContainsString( + 'exec runuser -u www-data -- "$@"', + $entrypoint + ); $this->assertDoesNotMatchRegularExpression('/^\s*php artisan /m', $entrypoint); } + public function test_runtime_image_installs_acl_tools_for_persistent_storage(): void + { + $dockerfile = file_get_contents(base_path('deploy/Dockerfile')); + + $this->assertIsString($dockerfile); + $this->assertStringContainsString("--no-install-recommends \\\n", $dockerfile); + $this->assertStringContainsString(" acl \\\n", $dockerfile); + $this->assertStringContainsString('libpq-dev', $dockerfile); + } + public function test_local_worker_healthcheck_and_initialization_use_web_user(): void { $compose = file_get_contents(base_path('docker-compose.local.yml'));