diff --git a/.editorconfig b/.editorconfig index 12bcb27e4ee7bbca7f74423a87d205926d2ad1d2..ccc6a281e51a2f99832b3c2d5b7b42b3ce84c36e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,3 @@ indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true - -[{composer.json,composer.lock}] -indent_size = 4 diff --git a/composer.json b/composer.json index 8938e1fb41eb15da7e8b9313167ed5464ebd6c1a..540721323dc08497663bd71f0372a45e068cd502 100644 --- a/composer.json +++ b/composer.json @@ -1,67 +1,76 @@ { - "name": "lakedrops/docker4drupal", - "description": "Composer Plugin to prepare local Drupal development environment for Docker.", - "type": "composer-plugin", - "keywords": ["Drupal", "Development", "Docker"], - "homepage": "https://gitlab.lakedrops.com/composer/plugin/docker4drupal", - "license": "GPL-2.0-or-later", - "authors": [ - { - "name": "Jürgen Haas", - "email": "juergen.haas@lakedrops.com", - "homepage": "https://www.lakedrops.com", - "role": "Drupal Expert" - }, - { - "name": "Daniel Speicher", - "email": "daniel.speicher@lakedrops.com", - "homepage": "https://www.lakedrops.com", - "role": "Drupal Expert" - }, - { - "name": "Richard Papp", - "email": "richard.papp@lakedrops.com", - "homepage": "https://www.lakedrops.com", - "role": "Drupal Expert" - } - ], - "support": { - "issues": "https://gitlab.lakedrops.com/composer/plugin/docker4drupal/issues", - "source": "https://gitlab.lakedrops.com/composer/plugin/docker4drupal/tree/main", - "docs": "https://devops-tools.docs.lakedrops.com/composer/plugin/d4d/" + "name": "lakedrops/docker4drupal", + "description": "Composer Plugin to prepare local Drupal development environment for Docker.", + "type": "composer-plugin", + "keywords": [ + "Drupal", + "Development", + "Docker" + ], + "homepage": "https://gitlab.lakedrops.com/composer/plugin/docker4drupal", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Jürgen Haas", + "email": "juergen.haas@lakedrops.com", + "homepage": "https://www.lakedrops.com", + "role": "Drupal Expert" }, - "require": { - "php": ">=7.4", - "ext-json": "*", - "composer-plugin-api": "^1||^2", - "henrywhitaker3/healthchecks-io": "^1.0", - "lakedrops/ahoy": "^1.7||dev-develop", - "lakedrops/composer-json-utils": "^2.4||dev-develop", - "lakedrops/docker-traefik": "^3.2||dev-develop" + { + "name": "Daniel Speicher", + "email": "daniel.speicher@lakedrops.com", + "homepage": "https://www.lakedrops.com", + "role": "Drupal Expert" }, - "require-dev": { - "composer/composer": "^1||^2", - "drupal/coder": "^8.3", - "lakedrops/drupal-environment": "^3.0", - "phpunit/phpunit": "^9.5", - "roave/security-advisories": "dev-master", - "squizlabs/php_codesniffer": "^3.7" - }, - "minimum-stability": "dev", - "prefer-stable": true, - "autoload": { - "psr-4": { - "LakeDrops\\Docker4Drupal\\": "src/" - } - }, - "extra": { - "class": "LakeDrops\\Docker4Drupal\\Plugin" - }, - "config": { - "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, - "lakedrops/ahoy": false, - "lakedrops/drupal-environment": false - } + { + "name": "Richard Papp", + "email": "richard.papp@lakedrops.com", + "homepage": "https://www.lakedrops.com", + "role": "Drupal Expert" + } + ], + "support": { + "issues": "https://gitlab.lakedrops.com/composer/plugin/docker4drupal/issues", + "source": "https://gitlab.lakedrops.com/composer/plugin/docker4drupal/tree/main", + "docs": "https://devops-tools.docs.lakedrops.com/composer/plugin/d4d/" + }, + "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + } + ], + "require": { + "php": ">=8.1", + "ext-json": "*", + "composer-plugin-api": "^2", + "henrywhitaker3/healthchecks-io": "^1.0", + "lakedrops/ahoy": "^1.7||dev-develop", + "lakedrops/composer-json-utils": "^2.4||dev-develop", + "lakedrops/docker-traefik": "^3.2||dev-develop" + }, + "require-dev": { + "composer/composer": "^2", + "lakedrops/drupal-development-environment": "^3.2||dev-develop", + "roave/security-advisories": "dev-latest" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "autoload": { + "psr-4": { + "LakeDrops\\Docker4Drupal\\": "src/" + } + }, + "extra": { + "class": "LakeDrops\\Docker4Drupal\\Plugin" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "drupal/core-composer-scaffold": false, + "lakedrops/*": false, + "php-http/discovery": false, + "phpstan/extension-installer": true } + } } diff --git a/src/CommandProvider.php b/src/CommandProvider.php index 64796d079e25ed4038ce0d8d491942ed01691bc2..9bd01cc558625a41615ad3a924fd5ac2f090efc5 100644 --- a/src/CommandProvider.php +++ b/src/CommandProvider.php @@ -3,14 +3,16 @@ namespace LakeDrops\Docker4Drupal; use Composer\Plugin\Capability\CommandProvider as CommandProviderCapability; -use Composer\Command\BaseCommand; +/** + * Composer Command Provider for Docker for Drupal. + * + * @package LakeDrops\Docker4Drupal + */ class CommandProvider implements CommandProviderCapability { /** - * Retrieves an array of commands - * - * @return BaseCommand[] + * {@inheritdoc} */ public function getCommands(): array { return [ @@ -18,4 +20,5 @@ class CommandProvider implements CommandProviderCapability { new UpdateCommand(), ]; } + } diff --git a/src/Handler.php b/src/Handler.php index 7457e49d8f4c3c4f4f9a1e6779f6dc3dcdffa136..71349118e19e6867292774b1b3059a267d3c301a 100644 --- a/src/Handler.php +++ b/src/Handler.php @@ -120,6 +120,16 @@ class Handler extends BaseHandler { 'webserver' => [ 'type' => 'apache', 'overwriteconfig' => FALSE, + 'responseheader' => [ + 'server' => '', + 'strict_transport_security' => 'max-age=31536000; includeSubDomains', + 'referrer_policy' => 'same-origin', + 'permissions_policy' => 'accelerometer=(), camera=(), geolocation=(), gyroscope=(), microphone=(), payment=(), usb=()', + 'cross_origin_embedder_policy' => 'credentialless', + 'cross_origin_opener_policy' => 'same-origin', + 'cross_origin_resource_policy' => 'cross-origin', + 'x_permitted_cross_domain_policies' => 'none', + ], ], 'mailhog' => [ 'enable' => 0, @@ -497,7 +507,7 @@ class Handler extends BaseHandler { $settingsPhpFile = $settingsPath . '/settings.php'; if ($fs->exists($settingsPhpFile)) { $settingsPhp = file_get_contents($settingsPhpFile); - if (strpos($settingsPhp, 'settings.docker.php') === FALSE) { + if (!str_contains($settingsPhp, 'settings.docker.php')) { $settingsPhp .= "\n\nif (file_exists(__DIR__ . '/settings.docker.php')) {\n include __DIR__ . '/settings.docker.php';\n}\n"; $fs->chmod($settingsPhpFile, 0664); file_put_contents($settingsPhpFile, $settingsPhp); @@ -702,7 +712,7 @@ class Handler extends BaseHandler { try { $hj_checks = $hj_manager->listChecks(); } - catch (HealthchecksFailureException | HealthchecksUnauthorisedException $e) { + catch (HealthchecksFailureException | HealthchecksUnauthorisedException) { // Ignoring this for now. } } @@ -747,7 +757,7 @@ class Handler extends BaseHandler { $hj_check = new Healthchecks($uuid, $hj_url . '/ping/'); $hj_check->success(); } - catch (HealthchecksFailureException | HealthchecksUuidNotFoundException | HealthchecksAccountLimitReachedException | HealthchecksUnauthorisedException $e) { + catch (HealthchecksFailureException | HealthchecksUuidNotFoundException | HealthchecksAccountLimitReachedException | HealthchecksUnauthorisedException) { // Ignoring this for now. } } @@ -764,7 +774,7 @@ class Handler extends BaseHandler { try { $check = $hj_manager->updateCheck($uuid, $task); } - catch (HealthchecksFailureException | HealthchecksUuidNotFoundException | HealthchecksAccountLimitReachedException | HealthchecksUnauthorisedException $e) { + catch (HealthchecksFailureException | HealthchecksUuidNotFoundException | HealthchecksAccountLimitReachedException | HealthchecksUnauthorisedException) { // Ignoring this for now. } } @@ -815,7 +825,7 @@ class Handler extends BaseHandler { * @return string|array * The ipv4 address(es). */ - private function getLocalIpv4(string $interface = NULL) { + private function getLocalIpv4(string $interface = NULL): array|string { $out = explode(PHP_EOL, shell_exec('LC_ALL=C /sbin/ifconfig')); $local_addrs = []; $ifname = 'unknown'; @@ -886,7 +896,7 @@ class Handler extends BaseHandler { return $mount['Source']; } } - elseif (strpos($projectRoot, $mount['Destination']) === 0) { + elseif (str_starts_with($projectRoot, $mount['Destination'])) { return $mount['Source'] . substr($projectRoot, strlen($mount['Destination'])); } } @@ -922,7 +932,7 @@ class Handler extends BaseHandler { return json_decode(implode('', $output), TRUE, 512, JSON_THROW_ON_ERROR)[0]; } } - catch (\Exception $ex) { + catch (\Exception) { // Ignore. } return [ @@ -945,7 +955,7 @@ class Handler extends BaseHandler { exec('docker network inspect traefik-public', $output); return json_decode(implode('', $output), TRUE, 512, JSON_THROW_ON_ERROR)[0]; } - catch (\Exception $ex) { + catch (\Exception) { // Ignore. } return [ diff --git a/src/Plugin.php b/src/Plugin.php index 8160aa0bea5bf60417dcc1a180363a8ab61e6cd1..b47d7b53318b9f66c680d09a3b9848104fe191e2 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -2,6 +2,7 @@ namespace LakeDrops\Docker4Drupal; +use Composer\Plugin\Capability\CommandProvider as ComposerCommandProvider; use Composer\Script\Event; use Composer\Script\ScriptEvents; use LakeDrops\Component\Composer\BasePlugin; @@ -23,7 +24,7 @@ class Plugin extends BasePlugin { */ public function getCapabilities(): array { return [ - \Composer\Plugin\Capability\CommandProvider::class => CommandProvider::class, + ComposerCommandProvider::class => CommandProvider::class, ]; } diff --git a/src/TraefikRewriteCommand.php b/src/TraefikRewriteCommand.php index 298e42538f7a1879080eb805f6e8528bafd97f82..c9883a19bcf7f328155ea6cf71be17df23dfa57f 100644 --- a/src/TraefikRewriteCommand.php +++ b/src/TraefikRewriteCommand.php @@ -6,12 +6,17 @@ use LakeDrops\Component\Composer\BaseCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +/** + * Composer Traefik Rewrite Command for Docker4Drupal. + * + * @package LakeDrops\Docker4Drupal + */ class TraefikRewriteCommand extends BaseCommand { /** * {@inheritdoc} */ - protected function configure() { + protected function configure(): void { $this->setName('lakedrops:traefik:rewrite'); $this->setDescription('Rewrite Traefik config on this host.'); } diff --git a/src/UpdateCommand.php b/src/UpdateCommand.php index ca8bd9dee125dbc541131d65c6a213a641c8e246..c2db2cce50927da246ddbdb8dc98df88a2e459dc 100644 --- a/src/UpdateCommand.php +++ b/src/UpdateCommand.php @@ -6,12 +6,17 @@ use LakeDrops\Component\Composer\BaseCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +/** + * Composer Update Command for Docker4Drupal. + * + * @package LakeDrops\Docker4Drupal + */ class UpdateCommand extends BaseCommand { /** * {@inheritdoc} */ - protected function configure() { + protected function configure(): void { $this->setName('lakedrops:docker4drupal'); $this->setDescription('(Re-)Configure Docker for Drupal for this project.'); } diff --git a/templates/docker-compose.yml.twig b/templates/docker-compose.yml.twig index 83bae2da503da122376cd4b977d02e57b3c9785e..5d0c059e1dc912761c7096965544238a1ff45464 100644 --- a/templates/docker-compose.yml.twig +++ b/templates/docker-compose.yml.twig @@ -49,10 +49,8 @@ services: restart: unless-stopped {% endif %} environment: -{% if mailhog.enable %} - PHP_SENDMAIL_PATH: /usr/sbin/sendmail -t -i -S mailhog:1025 -{% elseif mailpit.enable %} - PHP_SENDMAIL_PATH: /usr/sbin/sendmail -t -i -S mailpit:1025 +{% if mailhog.enable or mailpit.enable %} + PHP_SENDMAIL_PATH: /usr/sbin/sendmail -t -i -S {% if mailhog.enable %}mailhog{% else %}mailpit{% endif %}:1025 {% endif %} DB_HOST: mariadb DB_USER: drupal @@ -157,6 +155,17 @@ services: labels: traefik.enable: 'true' traefik.docker.network: traefik-public + traefik.http.routers.{{ webserver.type }}-{{ projectname }}.middlewares: {{ webserver.type }}-{{ projectname }}-middleware + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-middleware.chain.middlewares: {{ webserver.type }}-{{ projectname }}-headers@docker{% if basicauth.enable %},{{ webserver.type }}-{{ projectname }}-auth@docker{% endif %}{% for domain in extradomains %},{{ webserver.type }}-{{ projectname }}-redirectregex{{ loop.index }}@docker{% endfor %} + + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.server: '{{ webserver.responseheader.server }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.strict-transport-security: '{{ webserver.responseheader.strict_transport_security }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.referrer-policy: '{{ webserver.responseheader.referrer_policy }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.permissions-policy: '{{ webserver.responseheader.permissions_policy }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.cross-origin-embedder-policy: '{{ webserver.responseheader.cross_origin_embedder_policy }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.cross-origin-opener-policy: '{{ webserver.responseheader.cross_origin_opener_policy }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.cross-origin-resource-policy: '{{ webserver.responseheader.cross_origin_resource_policy }}' + traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-headers.headers.customresponseheaders.x-permitted-cross-domain-policies: '{{ webserver.responseheader.x_permitted_cross_domain_policies }}' {% if basicauth.enable %} traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-auth.basicauth.users: {{ basicauth.code }} {% endif %} @@ -166,18 +175,6 @@ services: traefik.http.routers.{{ webserver.type }}-{{ projectname }}.tls: 'true' traefik.http.routers.{{ webserver.type }}-{{ projectname }}.tls.certresolver: lakedrops {% endif %} -{% if extradomains|default([]) and basicauth.enable %} - traefik.http.routers.{{ webserver.type }}-{{ projectname }}.middlewares: {{ webserver.type }}-{{ projectname }}-middleware - traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-middleware.chain.middlewares: {% for domain in extradomains %}{% if loop.index > 1 %},{% endif %}{{ webserver.type }}-{{ projectname }}-redirectregex{{ loop.index }}@docker{% endfor %},{{ webserver.type }}-{{ projectname }}-auth@docker -{% elseif extradomains|default([])|length == 1 %} - traefik.http.routers.{{ webserver.type }}-{{ projectname }}.middlewares: {{ webserver.type }}-{{ projectname }}-redirectregex1@docker -{% elseif extradomains|default([]) %} - traefik.http.routers.{{ webserver.type }}-{{ projectname }}.middlewares: {{ webserver.type }}-{{ projectname }}-middleware - traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-middleware.chain.middlewares: {% for domain in extradomains %}{% if loop.index > 1 %},{% endif %}{{ webserver.type }}-{{ projectname }}-redirectregex{{ loop.index }}@docker{% endfor %} - -{% elseif basicauth.enable %} - traefik.http.routers.{{ webserver.type }}-{{ projectname }}.middlewares: {{ webserver.type }}-{{ projectname }}-auth@docker -{% endif %} {% for domain in extradomains|default([]) %} traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-redirectregex{{ loop.index }}.redirectRegex.regex: "^https://{{ domain }}/(.*)" traefik.http.middlewares.{{ webserver.type }}-{{ projectname }}-redirectregex{{ loop.index }}.redirectRegex.replacement: "https://{{ projectdomain }}/$${1}" diff --git a/templates/drushrc.php.twig b/templates/drushrc.php.twig index 02e3e83abf5aab7b91d65ca12f65c60b590cffe0..b6ca3ae0b2b6b4faa749b42851ba082071872813 100644 --- a/templates/drushrc.php.twig +++ b/templates/drushrc.php.twig @@ -1,7 +1,7 @@ <?php -$options['structure-tables']['common'] = array('{{ drush.sql.tables.structure|join('\', \'')|raw }}'); -$options['skip-tables']['common'] = array('{{ drush.sql.tables.skip|join('\', \'')|raw }}'); +$options['structure-tables']['common'] = ['{{ drush.sql.tables.structure|join('\', \'')|raw }}']; +$options['skip-tables']['common'] = ['{{ drush.sql.tables.skip|join('\', \'')|raw }}']; $options['shell-aliases']['pull-sql'] = '!drush -y --create-db --structure-tables-key=common --skip-tables-list={{ drush.sql.tables.skip|join(',') }} sql-sync @live @dev && drush -y @dev {{ (drupal.version >= 8) ? 'cr' : 'cc all' }} && drush -y @dev dev on'; $options['shell-aliases']['pull-files'] = '!drush -y rsync @live:%files @dev:%files --mode=rlDzq --chown=www-data:www-data --safe-links --max-size=20M && drush -y rsync @live:%private @dev:%private --mode=rlDzq --chown=www-data:www-data --safe-links --max-size=20M'; diff --git a/templates/settings.docker.php.twig b/templates/settings.docker.php.twig index 6ce920086f80a75640d772b70b4cf90f401a2536..9b40db1ed83f7fc3b338e00258cd3f956bb9af89 100644 --- a/templates/settings.docker.php.twig +++ b/templates/settings.docker.php.twig @@ -3,9 +3,9 @@ {% if drupal.version >= 8 %} {% if docker0.proxy %} $settings['reverse_proxy'] = TRUE; -$settings['reverse_proxy_addresses'] = array("{{ docker0.proxy }}"); +$settings['reverse_proxy_addresses'] = ["{{ docker0.proxy }}"]; {% endif %} -$settings['trusted_host_patterns'] = array( +$settings['trusted_host_patterns'] = [ '^{{ projectdomain|replace({".": "\\."}) }}$', {% for domain in extradomains|default([]) %} '^{{ domain|replace({".": "\\."}) }}$', @@ -13,10 +13,10 @@ $settings['trusted_host_patterns'] = array( {% if not drupal.live|default(0) %} '^{{ webserver.type }}$', {% endif %} -); -$databases = array( - 'default' => array( - 'default' => array( +]; +$databases = [ + 'default' => [ + 'default' => [ 'driver' => 'mysql', 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 'database' => 'drupal', @@ -30,9 +30,9 @@ $databases = array( 'init_commands' => [ 'isolation_level' => 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', ], - ), - ), -); + ], + ], +]; {% if not drupal.live|default(0) or mailhog.enable or mailpit.enable or symfony_mailer.enable %} $config['system.mail']['interface']['default'] = '{% if symfony_mailer.enable %}symfony_mailer{% else %}SMTPMailSystem{% endif %}'; {% if symfony_mailer.enable %} @@ -58,9 +58,9 @@ $config['smtp.settings']['smtp_password'] = ''; $settings['danse_notification_delivery'] = {{ drupal.danse_notification_delivery|default('FALSE') }}; {% endif %} {% elseif drupal.version <= 7 %} -$databases = array( - 'default' => array( - 'default' => array( +$databases = [ + 'default' => [ + 'default' => [ 'driver' => 'mysql', 'host' => 'mariadb', 'username' => 'drupal', @@ -72,9 +72,9 @@ $databases = array( 'init_commands' => [ 'isolation_level' => 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', ], - ), - ), -); + ], + ], +]; $base_url = '{{ projectprotocol }}://{{ projectdomain }}{{ projectport }}'; $conf['smtp_host'] = '{% if mailhog.enable %}mailhog{% else %}mailpit{% endif %}';