Skip to content

fix(media): align Apache static-asset CSP across recipes - #270

Merged
Jonas Elfering (keulinho) merged 5 commits into
mainfrom
codex/static-html-svg-csp
Oct 16, 2026
Merged

Jonas Elfering (keulinho) merged 5 commits into
mainfrom
codex/static-html-svg-csp

Conversation

@keulinho

@keulinho Jonas Elfering (keulinho) commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

1. Why is this change necessary?

Static assets are served directly by the webserver and do not receive application response policies. Stored HTML and SVG need CSP protection while application-rendered pages and bundled HTML applications retain their existing behavior.

2. What does this change do, exactly?

Update all six production public/.htaccess.dist copies in the shopware/core and shopware/platform 6.4, 6.6 and 6.7 recipes. Existing media/thumbnail HTML and static SVG receive script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'. Preserve each recipe's existing missing-file behavior, application-rendered HTML and bundled HTML behavior.

Images and styles remain permitted. Custom static documents must work without scripts, embedded documents, base URL overrides or form submissions. Fastly snippets remain unchanged: they already preserve the CSP response header from the origin.

3. Describe each step to reproduce the issue or behaviour.

  1. Serve an existing HTML file under media/ or thumbnail/, and an SVG file.
  2. Check the response for the full CSP above.
  3. Open a bundled HTML application or an application-rendered page; its response policy should retain its existing behavior.

Validation: 90 Apache HTTP cases passed, 15 per template, using the actual six files and a fixture PHP application. Checked both the older front-controller fallback and the 6.7 missing-media 404 behavior. Fastly files and the README match the base branch exactly. Whitespace checks pass. No test harness is included in this PR.

4. Please link to the relevant issues (if any).

5. Checklist

  • I have tested the changed configuration
  • I have checked that rendered HTML and bundled HTML applications retain their behavior
  • I have checked whitespace and syntax where applicable
  • Complete repository CI before merging

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Thanks for the PR 😍

How to test these changes in your application

  1. Add the Shopware flex endpoint in your composer.json to https://raw.githubusercontent.com/shopware/recipes/flex/pull-270/index.json.

    # When jq is installed
    jq '.extra.symfony.endpoint |= [ "https://raw.githubusercontent.com/shopware/recipes/flex/pull-270/index.json" ] + .' composer.json > composer.tmp && mv composer.tmp composer.json

    or manually

    "endpoint": [
        "https://raw.githubusercontent.com/shopware/recipes/flex/pull-270/index.json",
        "https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json",
        "flex://defaults"
    ]
    # On Unix-like (BSD, Linux and macOS)
    export SYMFONY_ENDPOINT=https://raw.githubusercontent.com/shopware/recipes/flex/pull-270/index.json
    # On Windows
    SET SYMFONY_ENDPOINT=https://raw.githubusercontent.com/shopware/recipes/flex/pull-270/index.json
  2. Install the package(s) related to this recipe:

    composer req 'shopware/core:^6.7' 'shopware/platform:^6.7'

Diff between recipe versions

In order to help with the review stage, I'm in charge of computing the diff between the various versions of patched recipes.
I'm going keep this comment up to date with any updates of the attached patch.

shopware/core

6.4 vs 6.6
diff --git a/shopware/core/6.4/bin/ci b/shopware/core/6.6/bin/ci
index e9f453b..661c0fa 100755
--- a/shopware/core/6.4/bin/ci
+++ b/shopware/core/6.6/bin/ci
@@ -3,7 +3,6 @@
 
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
-use Shopware\Core\HttpKernel;
 use Symfony\Bundle\FrameworkBundle\Console\Application;
 use Symfony\Component\Console\Input\ArgvInput;
 
@@ -39,18 +38,12 @@ return static function (array &$context) {
         $_SERVER['DATABASE_URL'] = 'mysql://_placeholder.test';
     }
 
-    if (method_exists(KernelFactory::class, "create")) {
-        $kernel = KernelFactory::create(
-            environment: $env,
-            debug: $debug,
-            classLoader: $classLoader,
-            pluginLoader: new ComposerPluginLoader($classLoader, null)
-        );
-    } else {
-        $kernel = new HttpKernel($env, $debug, $classLoader);
-        $kernel->setPluginLoader(new ComposerPluginLoader($classLoader, null));
-        $kernel = $kernel->getKernel();
-    }
+    $kernel = KernelFactory::create(
+        environment: $env,
+        debug: $debug,
+        classLoader: $classLoader,
+        pluginLoader: new ComposerPluginLoader($classLoader, null),
+    );
 
     $application = new Application($kernel);
     $kernel->boot();
diff --git a/shopware/core/6.4/bin/console b/shopware/core/6.6/bin/console
index 6ec51be..d6a05ca 100755
--- a/shopware/core/6.4/bin/console
+++ b/shopware/core/6.6/bin/console
@@ -2,9 +2,9 @@
 <?php
 
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
+use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\DbalKernelPluginLoader;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\StaticKernelPluginLoader;
-use Shopware\Core\HttpKernel;
 use Shopware\Core\Kernel;
 use Symfony\Bundle\FrameworkBundle\Console\Application;
 use Symfony\Component\Console\Input\ArgvInput;
@@ -40,25 +40,21 @@ return static function (array &$context) {
         $context['INSTALL'] = true;
     }
 
-    if (trim($context['DATABASE_URL'] ?? '') === '') {
-        // fake DATABASE_URL
-        $_SERVER['DATABASE_URL'] = 'mysql://_placeholder.test';
-    } else if (!isset($context['INSTALL'])) {
-        $pluginLoader = new DbalKernelPluginLoader($classLoader, null, \Shopware\Core\Kernel::getConnection());
+    if (!isset($context['INSTALL'])) {
+        $useComposerPluginLoader = (bool) ($context['COMPOSER_PLUGIN_LOADER'] ?? false);
+        if ($useComposerPluginLoader) {
+            $pluginLoader = new ComposerPluginLoader($classLoader, null);
+        } elseif (trim($context['DATABASE_URL'] ?? '') !== '') {
+            $pluginLoader = new DbalKernelPluginLoader($classLoader, null, Kernel::getConnection());
+        }
     }
 
-    if (method_exists(KernelFactory::class, "create")) {
-        $kernel = KernelFactory::create(
-            environment: $env,
-            debug: $debug,
-            classLoader: $classLoader,
-            pluginLoader: $pluginLoader
-        );
-    } else {
-        $kernel = new HttpKernel($env, $debug, $classLoader);
-        $kernel->setPluginLoader($pluginLoader);
-        $kernel = $kernel->getKernel();
-    }
+    $kernel = KernelFactory::create(
+        environment: $env,
+        debug: $debug,
+        classLoader: $classLoader,
+        pluginLoader: $pluginLoader,
+    );
 
     $application = new Application($kernel);
     $kernel->boot();
diff --git a/shopware/core/6.4/config/packages/shopware.yaml b/shopware/core/6.4/config/packages/shopware.yaml
deleted file mode 100644
index 0ecf72d..0000000
--- a/shopware/core/6.4/config/packages/shopware.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-# Using the webupdater will overwrite this file. Create a second file z-shopware.yaml to override the config
-
-shopware:
-    auto_update:
-        # Disables the auto updater in the UI
-#        enabled: false
-    admin_worker:
-# The Admin worker should be disabled on production server.
-#       enable_admin_worker: false
diff --git a/shopware/core/6.4/manifest.json b/shopware/core/6.6/manifest.json
index 0ce5f07..785a8f3 100644
--- a/shopware/core/6.4/manifest.json
+++ b/shopware/core/6.6/manifest.json
@@ -62,8 +62,7 @@
         "!/var/.htaccess",
         "/auth.json",
         "/install.lock",
-        "/public/asset-manifest.json",
-        "/files/asset-manifest.json"
+        "/public/asset-manifest.json"
     ],
     "composer-scripts": {
         "assets:install": "symfony-cmd"
diff --git a/shopware/core/6.4/post-install.txt b/shopware/core/6.6/post-install.txt
index 36869a6..18d1b8f 100644
--- a/shopware/core/6.4/post-install.txt
+++ b/shopware/core/6.6/post-install.txt
@@ -19,8 +19,3 @@
     5. Optional: Open the Mail catcher with symfony open:local:webmail
 
   * Read the documentation at https://developer.shopware.com/
-
-  * Warning if updating from older versions of the production template:
-
-    There might be old `require-dev` dependencies in your `composer.json` file. Please remove them before updating shopware/core to versions >= v6.4.
-    You can do it using this command: composer config --unset require-dev
diff --git a/shopware/core/6.4/public/index.php b/shopware/core/6.6/public/index.php
index eb330c6..fe36139 100644
--- a/shopware/core/6.4/public/index.php
+++ b/shopware/core/6.6/public/index.php
@@ -2,13 +2,8 @@
 
 use Shopware\Core\DevOps\Environment\EnvironmentHelper;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
-use Shopware\Core\HttpKernel;
 use Shopware\Core\Installer\InstallerKernel;
-use Symfony\Component\HttpFoundation\Request;
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Symfony\Component\HttpKernel\TerminableInterface;
 
 $_SERVER['SCRIPT_FILENAME'] = __FILE__;
 
@@ -34,62 +29,20 @@ return function (array $context) {
     $appEnv = $context['APP_ENV'] ?? 'dev';
     $debug = (bool) ($context['APP_DEBUG'] ?? ($appEnv !== 'prod'));
 
-    $trustedProxies = $context['TRUSTED_PROXIES'] ?? false;
-    if ($trustedProxies) {
-        Request::setTrustedProxies(
-            explode(',', $trustedProxies),
-            Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO
-        );
-    }
-
-    $trustedHosts = $context['TRUSTED_HOSTS'] ?? false;
-    if ($trustedHosts) {
-        Request::setTrustedHosts(explode(',', $trustedHosts));
-    }
-
     if (!EnvironmentHelper::getVariable('SHOPWARE_SKIP_WEBINSTALLER', false) && !file_exists(dirname(__DIR__) . '/install.lock')) {
         return new InstallerKernel($appEnv, $debug);
     }
 
-    if (method_exists(KernelFactory::class, "create")) {
-        $pluginLoader = null;
-        if (EnvironmentHelper::getVariable('COMPOSER_PLUGIN_LOADER', false)) {
-            $pluginLoader = new ComposerPluginLoader($classLoader, null);
-        }
-
-        return KernelFactory::create(
-            environment: $appEnv,
-            debug: $debug,
-            classLoader: $classLoader,
-            pluginLoader: $pluginLoader
-        );
-    }
-
-    $shopwareHttpKernel = new HttpKernel($appEnv, $debug, $classLoader);
+    $pluginLoader = null;
 
     if (EnvironmentHelper::getVariable('COMPOSER_PLUGIN_LOADER', false)) {
-        $shopwareHttpKernel->setPluginLoader(
-            new ComposerPluginLoader($classLoader, null)
-        );
+        $pluginLoader = new ComposerPluginLoader($classLoader, null);
     }
 
-    return new class($shopwareHttpKernel) implements HttpKernelInterface, TerminableInterface {
-        private HttpKernel $httpKernel;
-
-        public function __construct(HttpKernel $httpKernel)
-        {
-            $this->httpKernel = $httpKernel;
-        }
-
-        public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response
-        {
-            return $this->httpKernel->handle($request, $type, $catch)->getResponse();
-        }
-
-        public function terminate(Request $request, Response $response): void
-        {
-            $this->httpKernel->terminate($request, $response);
-        }
-    };
+    return KernelFactory::create(
+        environment: $appEnv,
+        debug: $debug,
+        classLoader: $classLoader,
+        pluginLoader: $pluginLoader,
+    );
 };
-
6.6 vs 6.7
diff --git a/shopware/core/6.6/manifest.json b/shopware/core/6.7/manifest.json
index 785a8f3..6f01a6e 100644
--- a/shopware/core/6.6/manifest.json
+++ b/shopware/core/6.7/manifest.json
@@ -30,6 +30,9 @@
         ],
         "Shopware\\Core\\Profiling\\Profiling": [
             "all"
+        ],
+        "Shopware\\Core\\Service\\Service": [
+            "all"
         ]
     },
     "container": {
@@ -43,9 +46,7 @@
         "APP_SECRET": "%generate(secret)%",
         "INSTANCE_ID": "%generate(secret)%",
         "BLUE_GREEN_DEPLOYMENT": "0",
-        "DATABASE_URL": "mysql://root:root@localhost/shopware",
-        "#1": "With Shopware 6.4.17.0 the MAILER_DSN variable will be used in this template instead of MAILER_URL",
-        "MAILER_URL": "null://null"
+        "DATABASE_URL": "mysql://root:root@localhost/shopware"
     },
     "gitignore": [
         ".env.local",
diff --git a/shopware/core/6.6/public/.htaccess.dist b/shopware/core/6.7/public/.htaccess.dist
index bf32313..3e64081 100644
--- a/shopware/core/6.6/public/.htaccess.dist
+++ b/shopware/core/6.7/public/.htaccess.dist
@@ -30,6 +30,7 @@ DirectoryIndex index.php
     RewriteRule ^ - [L]
 
     # Rewrite all other queries to the front controller.
+    RewriteCond %{REQUEST_URI} !^/(theme|media|thumbnail|bundles|css|fonts|js|recovery)/ [NC]
     RewriteRule ^ %{ENV:BASE}/index.php [L]
 </IfModule>
 
diff --git a/shopware/core/6.6/public/index.php b/shopware/core/6.7/public/index.php
index fe36139..1fc45df 100644
--- a/shopware/core/6.6/public/index.php
+++ b/shopware/core/6.7/public/index.php
@@ -2,6 +2,7 @@
 
 use Shopware\Core\DevOps\Environment\EnvironmentHelper;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
+use Shopware\Core\Installer\Helper\InstallerRedirectHelper;
 use Shopware\Core\Installer\InstallerKernel;
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
 
@@ -21,7 +22,14 @@ return function (array $context) {
         $baseURL = rtrim($baseURL, '/');
 
         if (strpos($_SERVER['REQUEST_URI'], '/installer') === false) {
-            header('Location: ' . $baseURL . '/installer');
+            // InstallerRedirectHelper was introduced in 6.7.5.0; older 6.7 patch releases
+            // ship no such class, so forward the sanitised query only when it is available.
+            $query = match (true) {
+                class_exists(InstallerRedirectHelper::class) => (new InstallerRedirectHelper($_SERVER))->buildQueryString(),
+                default => '',
+            };
+
+            header('Location: ' . $baseURL . '/installer' . $query);
             exit;
         }
     }
diff --git a/shopware/core/6.6/root/.htaccess b/shopware/core/6.7/root/.htaccess
index 6c961e7..8d2e431 100644
--- a/shopware/core/6.6/root/.htaccess
+++ b/shopware/core/6.7/root/.htaccess
@@ -1,3 +1,5 @@
+# This file will be overwritten on any Shopware Update. For adjustments edit the .htaccess file inside the public folder
+
 DirectoryIndex index.html index.php
 
 <IfModule mod_negotiation.c>

shopware/platform

6.4 vs 6.6
diff --git a/shopware/platform/6.4/bin/build-administration.sh b/shopware/platform/6.6/bin/build-administration.sh
index dbd6065..f7cc64c 100755
--- a/shopware/platform/6.4/bin/build-administration.sh
+++ b/shopware/platform/6.6/bin/build-administration.sh
@@ -5,6 +5,9 @@ CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
 
 export PROJECT_ROOT="${PROJECT_ROOT:-"$(dirname "$CWD")"}"
 export ENV_FILE=${ENV_FILE:-"${PROJECT_ROOT}/.env"}
+export NPM_CONFIG_FUND=false
+export NPM_CONFIG_AUDIT=false
+export NPM_CONFIG_UPDATE_NOTIFIER=false
 
 # shellcheck source=functions.sh
 source "${PROJECT_ROOT}/bin/functions.sh"
@@ -73,7 +76,7 @@ else
     echo "Cannot check extensions for required npm installations as jq is not installed"
 fi
 
-(cd "${ADMIN_ROOT}"/Resources/app/administration && npm install --no-audit --prefer-offline)
+(cd "${ADMIN_ROOT}"/Resources/app/administration && npm install --prefer-offline --omit=dev)
 
 # Dump entity schema
 if [[ -z "${SHOPWARE_SKIP_ENTITY_SCHEMA_DUMP:-""}" ]] && [[ -f "${ADMIN_ROOT}"/Resources/app/administration/scripts/entitySchemaConverter/entity-schema-converter.ts ]]; then
diff --git a/shopware/platform/6.4/bin/build-storefront.sh b/shopware/platform/6.6/bin/build-storefront.sh
index f5ae8b0..7cb1914 100755
--- a/shopware/platform/6.4/bin/build-storefront.sh
+++ b/shopware/platform/6.6/bin/build-storefront.sh
@@ -8,6 +8,9 @@ set -euo pipefail
 export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
 export PUPPETEER_SKIP_DOWNLOAD=true
 export PROJECT_ROOT="${PROJECT_ROOT:-"$(dirname "$CWD")"}"
+export NPM_CONFIG_FUND=false
+export NPM_CONFIG_AUDIT=false
+export NPM_CONFIG_UPDATE_NOTIFIER=false
 
 if [[ -e "${PROJECT_ROOT}/vendor/shopware/platform" ]]; then
     STOREFRONT_ROOT="${STOREFRONT_ROOT:-"${PROJECT_ROOT}/vendor/shopware/platform/src/Storefront"}"
@@ -49,7 +52,7 @@ if [[ $(command -v jq) ]]; then
         if [[ -f "$path/package.json" && ! -d "$path/node_modules" && $name != "storefront" ]]; then
             echo "=> Installing npm dependencies for ${name}"
 
-            npm install --prefix "$path" --no-audit --prefer-offline
+            npm install --prefix "$path" --prefer-offline
         fi
     done
     cd "$OLDPWD" || exit
@@ -57,8 +60,12 @@ else
     echo "Cannot check extensions for required npm installations as jq is not installed"
 fi
 
-npm --prefix "${STOREFRONT_ROOT}"/Resources/app/storefront install --no-audit --prefer-offline
+npm --prefix "${STOREFRONT_ROOT}"/Resources/app/storefront install --prefer-offline --omit=dev
 node "${STOREFRONT_ROOT}"/Resources/app/storefront/copy-to-vendor.js
 npm --prefix "${STOREFRONT_ROOT}"/Resources/app/storefront run production
 [[ ${SHOPWARE_SKIP_ASSET_COPY:-""} ]] ||"${BIN_TOOL}" assets:install
-[[ ${SHOPWARE_SKIP_THEME_COMPILE:-""} ]] || "${BIN_TOOL}" theme:compile
+[[ ${SHOPWARE_SKIP_THEME_COMPILE:-""} ]] || "${BIN_TOOL}" theme:compile --active-only
+
+if ! [ "${1:-default}" = "--keep-cache" ]; then
+    "${BIN_TOOL}" cache:clear
+fi
diff --git a/shopware/platform/6.4/bin/ci b/shopware/platform/6.6/bin/ci
index e9f453b..661c0fa 100755
--- a/shopware/platform/6.4/bin/ci
+++ b/shopware/platform/6.6/bin/ci
@@ -3,7 +3,6 @@
 
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
-use Shopware\Core\HttpKernel;
 use Symfony\Bundle\FrameworkBundle\Console\Application;
 use Symfony\Component\Console\Input\ArgvInput;
 
@@ -39,18 +38,12 @@ return static function (array &$context) {
         $_SERVER['DATABASE_URL'] = 'mysql://_placeholder.test';
     }
 
-    if (method_exists(KernelFactory::class, "create")) {
-        $kernel = KernelFactory::create(
-            environment: $env,
-            debug: $debug,
-            classLoader: $classLoader,
-            pluginLoader: new ComposerPluginLoader($classLoader, null)
-        );
-    } else {
-        $kernel = new HttpKernel($env, $debug, $classLoader);
-        $kernel->setPluginLoader(new ComposerPluginLoader($classLoader, null));
-        $kernel = $kernel->getKernel();
-    }
+    $kernel = KernelFactory::create(
+        environment: $env,
+        debug: $debug,
+        classLoader: $classLoader,
+        pluginLoader: new ComposerPluginLoader($classLoader, null),
+    );
 
     $application = new Application($kernel);
     $kernel->boot();
diff --git a/shopware/platform/6.4/bin/console b/shopware/platform/6.6/bin/console
index 6ec51be..d6a05ca 100755
--- a/shopware/platform/6.4/bin/console
+++ b/shopware/platform/6.6/bin/console
@@ -2,9 +2,9 @@
 <?php
 
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
+use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\DbalKernelPluginLoader;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\StaticKernelPluginLoader;
-use Shopware\Core\HttpKernel;
 use Shopware\Core\Kernel;
 use Symfony\Bundle\FrameworkBundle\Console\Application;
 use Symfony\Component\Console\Input\ArgvInput;
@@ -40,25 +40,21 @@ return static function (array &$context) {
         $context['INSTALL'] = true;
     }
 
-    if (trim($context['DATABASE_URL'] ?? '') === '') {
-        // fake DATABASE_URL
-        $_SERVER['DATABASE_URL'] = 'mysql://_placeholder.test';
-    } else if (!isset($context['INSTALL'])) {
-        $pluginLoader = new DbalKernelPluginLoader($classLoader, null, \Shopware\Core\Kernel::getConnection());
+    if (!isset($context['INSTALL'])) {
+        $useComposerPluginLoader = (bool) ($context['COMPOSER_PLUGIN_LOADER'] ?? false);
+        if ($useComposerPluginLoader) {
+            $pluginLoader = new ComposerPluginLoader($classLoader, null);
+        } elseif (trim($context['DATABASE_URL'] ?? '') !== '') {
+            $pluginLoader = new DbalKernelPluginLoader($classLoader, null, Kernel::getConnection());
+        }
     }
 
-    if (method_exists(KernelFactory::class, "create")) {
-        $kernel = KernelFactory::create(
-            environment: $env,
-            debug: $debug,
-            classLoader: $classLoader,
-            pluginLoader: $pluginLoader
-        );
-    } else {
-        $kernel = new HttpKernel($env, $debug, $classLoader);
-        $kernel->setPluginLoader($pluginLoader);
-        $kernel = $kernel->getKernel();
-    }
+    $kernel = KernelFactory::create(
+        environment: $env,
+        debug: $debug,
+        classLoader: $classLoader,
+        pluginLoader: $pluginLoader,
+    );
 
     $application = new Application($kernel);
     $kernel->boot();
diff --git a/shopware/platform/6.4/bin/watch-administration.sh b/shopware/platform/6.6/bin/watch-administration.sh
index 93d9b9e..fc53b02 100755
--- a/shopware/platform/6.4/bin/watch-administration.sh
+++ b/shopware/platform/6.6/bin/watch-administration.sh
@@ -56,7 +56,7 @@ else
     echo "Cannot check extensions for required npm installations as jq is not installed"
 fi
 
-if [ ! -d vendor/shopware/administration/Resources/app/administration/node_modules ]; then
+if [ ! -d vendor/shopware/administration/Resources/app/administration/node_modules/webpack-dev-server ]; then
     npm install --prefix vendor/shopware/administration/Resources/app/administration/
 fi
 
diff --git a/shopware/platform/6.4/bin/watch-storefront.sh b/shopware/platform/6.6/bin/watch-storefront.sh
index f6c9015..735a0d2 100755
--- a/shopware/platform/6.4/bin/watch-storefront.sh
+++ b/shopware/platform/6.6/bin/watch-storefront.sh
@@ -4,6 +4,9 @@ CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
 
 export PROJECT_ROOT="${PROJECT_ROOT:-"$(dirname "$CWD")"}"
 export ENV_FILE=${ENV_FILE:-"${PROJECT_ROOT}/.env"}
+export NPM_CONFIG_FUND=false
+export NPM_CONFIG_AUDIT=false
+export NPM_CONFIG_UPDATE_NOTIFIER=false
 
 # shellcheck source=functions.sh
 source "${PROJECT_ROOT}/bin/functions.sh"
@@ -23,9 +26,24 @@ export PROXY_URL
 export STOREFRONT_ASSETS_PORT
 export STOREFRONT_PROXY_PORT
 
-DATABASE_URL="" "${CWD}"/console feature:dump
-"${CWD}"/console theme:compile
-"${CWD}"/console theme:dump
+if [[ -e "${PROJECT_ROOT}/vendor/shopware/platform" ]]; then
+    STOREFRONT_ROOT="${STOREFRONT_ROOT:-"${PROJECT_ROOT}/vendor/shopware/platform/src/Storefront"}"
+else
+    STOREFRONT_ROOT="${STOREFRONT_ROOT:-"${PROJECT_ROOT}/vendor/shopware/storefront"}"
+fi
+
+if [[ ! -d "${STOREFRONT_ROOT}"/Resources/app/storefront/node_modules/webpack-dev-server ]]; then
+    npm --prefix "${STOREFRONT_ROOT}"/Resources/app/storefront install --prefer-offline
+fi
+
+"${CWD}"/console bundle:dump
+"${CWD}"/console feature:dump
+"${CWD}"/console theme:compile --active-only
+if [[ -n "$1" ]]; then
+    "${CWD}"/console theme:dump --theme-name="$1"
+else
+    "${CWD}"/console theme:dump
+fi
 
 if [[ $(command -v jq) ]]; then
     OLDPWD=$(pwd)
@@ -55,4 +73,4 @@ else
     echo "Cannot check extensions for required npm installations as jq is not installed"
 fi
 
-npm --prefix vendor/shopware/storefront/Resources/app/storefront/ run-script hot-proxy
+npm --prefix "${STOREFRONT_ROOT}"/Resources/app/storefront run-script hot-proxy
diff --git a/shopware/platform/6.4/config/packages/elasticsearch.yaml b/shopware/platform/6.4/config/packages/elasticsearch.yaml
deleted file mode 100644
index 65f29c9..0000000
--- a/shopware/platform/6.4/config/packages/elasticsearch.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-elasticsearch:
-    hosts: "%env(string:OPENSEARCH_URL)%"
-
diff --git a/shopware/platform/6.4/config/packages/shopware.yaml b/shopware/platform/6.4/config/packages/shopware.yaml
deleted file mode 100644
index 0ecf72d..0000000
--- a/shopware/platform/6.4/config/packages/shopware.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-# Using the webupdater will overwrite this file. Create a second file z-shopware.yaml to override the config
-
-shopware:
-    auto_update:
-        # Disables the auto updater in the UI
-#        enabled: false
-    admin_worker:
-# The Admin worker should be disabled on production server.
-#       enable_admin_worker: false
diff --git a/shopware/platform/6.4/manifest.json b/shopware/platform/6.6/manifest.json
index b253598..f355e10 100644
--- a/shopware/platform/6.4/manifest.json
+++ b/shopware/platform/6.6/manifest.json
@@ -56,7 +56,7 @@
         "DATABASE_URL": "mysql:\/\/root:root@localhost\/shopware",
         "#1": "With Shopware 6.4.17.0 the MAILER_DSN variable will be used in this template instead of MAILER_URL",
         "MAILER_URL": "null:\/\/null",
-        "STOREFRONT_PROXY_URL": "http:\/\/localhost",
+        "PROXY_URL": "http:\/\/localhost",
         "SHOPWARE_HTTP_CACHE_ENABLED": "1",
         "SHOPWARE_HTTP_DEFAULT_TTL": "7200",
         "OPENSEARCH_URL": "http:\/\/localhost:9200",
@@ -80,8 +80,7 @@
         "!\/var\/.htaccess",
         "\/auth.json",
         "\/install.lock",
-        "\/public\/asset-manifest.json",
-        "\/files\/asset-manifest.json"
+        "\/public\/asset-manifest.json"
     ],
     "composer-scripts": {
         "assets:install": "symfony-cmd"
diff --git a/shopware/platform/6.4/post-install.txt b/shopware/platform/6.6/post-install.txt
index 36869a6..18d1b8f 100644
--- a/shopware/platform/6.4/post-install.txt
+++ b/shopware/platform/6.6/post-install.txt
@@ -19,8 +19,3 @@
     5. Optional: Open the Mail catcher with symfony open:local:webmail
 
   * Read the documentation at https://developer.shopware.com/
-
-  * Warning if updating from older versions of the production template:
-
-    There might be old `require-dev` dependencies in your `composer.json` file. Please remove them before updating shopware/core to versions >= v6.4.
-    You can do it using this command: composer config --unset require-dev
diff --git a/shopware/platform/6.4/public/index.php b/shopware/platform/6.6/public/index.php
index eb330c6..fe36139 100644
--- a/shopware/platform/6.4/public/index.php
+++ b/shopware/platform/6.6/public/index.php
@@ -2,13 +2,8 @@
 
 use Shopware\Core\DevOps\Environment\EnvironmentHelper;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
-use Shopware\Core\HttpKernel;
 use Shopware\Core\Installer\InstallerKernel;
-use Symfony\Component\HttpFoundation\Request;
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Symfony\Component\HttpKernel\TerminableInterface;
 
 $_SERVER['SCRIPT_FILENAME'] = __FILE__;
 
@@ -34,62 +29,20 @@ return function (array $context) {
     $appEnv = $context['APP_ENV'] ?? 'dev';
     $debug = (bool) ($context['APP_DEBUG'] ?? ($appEnv !== 'prod'));
 
-    $trustedProxies = $context['TRUSTED_PROXIES'] ?? false;
-    if ($trustedProxies) {
-        Request::setTrustedProxies(
-            explode(',', $trustedProxies),
-            Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO
-        );
-    }
-
-    $trustedHosts = $context['TRUSTED_HOSTS'] ?? false;
-    if ($trustedHosts) {
-        Request::setTrustedHosts(explode(',', $trustedHosts));
-    }
-
     if (!EnvironmentHelper::getVariable('SHOPWARE_SKIP_WEBINSTALLER', false) && !file_exists(dirname(__DIR__) . '/install.lock')) {
         return new InstallerKernel($appEnv, $debug);
     }
 
-    if (method_exists(KernelFactory::class, "create")) {
-        $pluginLoader = null;
-        if (EnvironmentHelper::getVariable('COMPOSER_PLUGIN_LOADER', false)) {
-            $pluginLoader = new ComposerPluginLoader($classLoader, null);
-        }
-
-        return KernelFactory::create(
-            environment: $appEnv,
-            debug: $debug,
-            classLoader: $classLoader,
-            pluginLoader: $pluginLoader
-        );
-    }
-
-    $shopwareHttpKernel = new HttpKernel($appEnv, $debug, $classLoader);
+    $pluginLoader = null;
 
     if (EnvironmentHelper::getVariable('COMPOSER_PLUGIN_LOADER', false)) {
-        $shopwareHttpKernel->setPluginLoader(
-            new ComposerPluginLoader($classLoader, null)
-        );
+        $pluginLoader = new ComposerPluginLoader($classLoader, null);
     }
 
-    return new class($shopwareHttpKernel) implements HttpKernelInterface, TerminableInterface {
-        private HttpKernel $httpKernel;
-
-        public function __construct(HttpKernel $httpKernel)
-        {
-            $this->httpKernel = $httpKernel;
-        }
-
-        public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response
-        {
-            return $this->httpKernel->handle($request, $type, $catch)->getResponse();
-        }
-
-        public function terminate(Request $request, Response $response): void
-        {
-            $this->httpKernel->terminate($request, $response);
-        }
-    };
+    return KernelFactory::create(
+        environment: $appEnv,
+        debug: $debug,
+        classLoader: $classLoader,
+        pluginLoader: $pluginLoader,
+    );
 };
-
6.6 vs 6.7
diff --git a/shopware/platform/6.6/bin/build-administration.sh b/shopware/platform/6.7/bin/build-administration.sh
index f7cc64c..acab644 100755
--- a/shopware/platform/6.6/bin/build-administration.sh
+++ b/shopware/platform/6.7/bin/build-administration.sh
@@ -1,4 +1,5 @@
 #!/usr/bin/env bash
+# shellcheck source-path=SCRIPTDIR
 
 unset CDPATH
 CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
@@ -23,10 +24,10 @@ set +o allexport
 
 set -euo pipefail
 
+export APP_URL
+export PROJECT_ROOT
 export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
 export PUPPETEER_SKIP_DOWNLOAD=true
-export DISABLE_ADMIN_COMPILATION_TYPECHECK=true
-export PROJECT_ROOT="${PROJECT_ROOT:-"$(dirname "$CWD")"}"
 
 if [[ -e "${PROJECT_ROOT}/vendor/shopware/platform" ]]; then
     ADMIN_ROOT="${ADMIN_ROOT:-"${PROJECT_ROOT}/vendor/shopware/platform/src/Administration"}"
@@ -34,6 +35,8 @@ else
     ADMIN_ROOT="${ADMIN_ROOT:-"${PROJECT_ROOT}/vendor/shopware/administration"}"
 fi
 
+export ADMIN_ROOT
+
 BIN_TOOL="${CWD}/console"
 
 if [[ ${CI:-""} ]]; then
@@ -51,9 +54,12 @@ fi
 if [[ $(command -v jq) ]]; then
     OLDPWD=$(pwd)
     cd "$PROJECT_ROOT" || exit
+    basePathsFile=$(mktemp)
+    trap 'rm -f "$basePathsFile"' EXIT
 
     jq -c '.[]' "var/plugins.json" | while read -r config; do
         srcPath=$(echo "$config" | jq -r '(.basePath + .administration.path)')
+        basePath=$(echo "$config" | jq -r '.basePath')
 
         # the package.json files are always one upper
         path=$(dirname "$srcPath")
@@ -65,12 +71,32 @@ if [[ $(command -v jq) ]]; then
             continue
         fi
 
+        if [[ -n $srcPath ]] && ! grep -qxF "$basePath" "$basePathsFile" 2>/dev/null; then
+            echo "$basePath" >> "$basePathsFile"
+        fi
+
         if [[ -f "$path/package.json" && ! -d "$path/node_modules" && $name != "administration" ]]; then
             echo "=> Installing npm dependencies for ${name}"
 
-            npm install --prefix "$path" --no-audit --prefer-offline
+            (cd "$path" && npm install --omit=dev --no-audit --prefer-offline)
         fi
     done
+
+    while IFS= read -r basePath || [[ -n "$basePath" ]]; do
+        if [[ -z $basePath ]]; then
+            continue
+        fi
+        if [[ -r "${basePath}/package.json" ]]; then
+            echo "=> Installing npm dependencies for ${basePath}"
+            (cd "${basePath}" && npm ci --omit=dev --no-audit --prefer-offline)
+        fi
+
+        if [[ -r "${basePath}/../package.json" ]]; then
+            echo "=> Installing npm dependencies for ${basePath}/.."
+            (cd "${basePath}/.." && npm ci --omit=dev --no-audit --prefer-offline)
+        fi
+    done < "$basePathsFile"
+
     cd "$OLDPWD" || exit
 else
     echo "Cannot check extensions for required npm installations as jq is not installed"
diff --git a/shopware/platform/6.6/bin/build-storefront.sh b/shopware/platform/6.7/bin/build-storefront.sh
index 7cb1914..be0d62c 100755
--- a/shopware/platform/6.6/bin/build-storefront.sh
+++ b/shopware/platform/6.7/bin/build-storefront.sh
@@ -35,9 +35,12 @@ fi
 if [[ $(command -v jq) ]]; then
     OLDPWD=$(pwd)
     cd "$PROJECT_ROOT" || exit
+    basePathsFile=$(mktemp)
+    trap 'rm -f "$basePathsFile"' EXIT
 
     jq -c '.[]' "var/plugins.json" | while read -r config; do
         srcPath=$(echo "$config" | jq -r '(.basePath + .storefront.path)')
+        basePath=$(echo "$config" | jq -r '.basePath')
 
         # the package.json files are always one upper
         path=$(dirname "$srcPath")
@@ -49,12 +52,32 @@ if [[ $(command -v jq) ]]; then
             continue
         fi
 
+        if [[ -n $srcPath ]] && ! grep -qxF "$basePath" "$basePathsFile" 2>/dev/null; then
+            echo "$basePath" >> "$basePathsFile"
+        fi
+
         if [[ -f "$path/package.json" && ! -d "$path/node_modules" && $name != "storefront" ]]; then
             echo "=> Installing npm dependencies for ${name}"
 
-            npm install --prefix "$path" --prefer-offline
+            (cd "$path" && npm install --prefer-offline)
         fi
     done
+
+    while IFS= read -r basePath || [[ -n "$basePath" ]]; do
+        if [[ -z $basePath ]]; then
+            continue
+        fi
+        if [[ -r "${basePath}/package.json" ]]; then
+            echo "=> Installing npm dependencies for ${basePath}"
+            (cd "${basePath}" && npm ci --omit=dev --no-audit --prefer-offline)
+        fi
+
+        if [[ -r "${basePath}/../package.json" ]]; then
+            echo "=> Installing npm dependencies for ${basePath}/.."
+            (cd "${basePath}/.." && npm ci --omit=dev --no-audit --prefer-offline)
+        fi
+    done < "$basePathsFile"
+
     cd "$OLDPWD" || exit
 else
     echo "Cannot check extensions for required npm installations as jq is not installed"
diff --git a/shopware/platform/6.6/bin/watch-administration.sh b/shopware/platform/6.7/bin/watch-administration.sh
index fc53b02..42900c8 100755
--- a/shopware/platform/6.6/bin/watch-administration.sh
+++ b/shopware/platform/6.7/bin/watch-administration.sh
@@ -18,10 +18,20 @@ eval "$curenv"
 set +o allexport
 
 export HOST=${HOST:-"localhost"}
-export ESLINT_DISABLE
-export PORT
+export VITE_HOST
+export ADMIN_PORT
 export APP_URL
-export DISABLE_ADMIN_COMPILATION_TYPECHECK=1
+export SHOPWARE_ADMIN_SKIP_SOURCEMAP_GENERATION
+export DISABLE_DEVSERVER_OPEN
+export DDEV_PRIMARY_URL
+
+if [[ -e "${PROJECT_ROOT}/vendor/shopware/platform" ]]; then
+    ADMIN_ROOT="${ADMIN_ROOT:-"${PROJECT_ROOT}/vendor/shopware/platform/src/Administration"}"
+else
+    ADMIN_ROOT="${ADMIN_ROOT:-"${PROJECT_ROOT}/vendor/shopware/administration"}"
+fi
+
+export ADMIN_ROOT
 
 BIN_TOOL="${CWD}/console"
 
@@ -48,7 +58,7 @@ if [[ $(command -v jq) ]]; then
         if [[ -f "$path/package.json" && ! -d "$path/node_modules" && $name != "administration" ]]; then
             echo "=> Installing npm dependencies for ${name}"
 
-            npm install --prefix "$path"
+            (cd "$path" && npm install --omit=dev)
         fi
     done
     cd "$OLDPWD" || exit
@@ -56,9 +66,7 @@ else
     echo "Cannot check extensions for required npm installations as jq is not installed"
 fi
 
-if [ ! -d vendor/shopware/administration/Resources/app/administration/node_modules/webpack-dev-server ]; then
-    npm install --prefix vendor/shopware/administration/Resources/app/administration/
-fi
+(cd "${ADMIN_ROOT}"/Resources/app/administration && npm install --prefer-offline)
 
 # Dump entity schema
 if [[ -z "${SHOPWARE_SKIP_ENTITY_SCHEMA_DUMP:-""}" ]] && [[ -f "${ADMIN_ROOT}"/Resources/app/administration/scripts/entitySchemaConverter/entity-schema-converter.ts ]]; then
@@ -67,4 +75,4 @@ if [[ -z "${SHOPWARE_SKIP_ENTITY_SCHEMA_DUMP:-""}" ]] && [[ -f "${ADMIN_ROOT}"/R
   (cd "${ADMIN_ROOT}"/Resources/app/administration && npm run convert-entity-schema)
 fi
 
-npm run --prefix vendor/shopware/administration/Resources/app/administration/ dev
+(cd "${ADMIN_ROOT}"/Resources/app/administration && npm run dev)
diff --git a/shopware/platform/6.6/bin/watch-storefront.sh b/shopware/platform/6.7/bin/watch-storefront.sh
index 735a0d2..46b0f3f 100755
--- a/shopware/platform/6.6/bin/watch-storefront.sh
+++ b/shopware/platform/6.7/bin/watch-storefront.sh
@@ -21,10 +21,12 @@ eval "$curenv"
 set +o allexport
 
 export APP_URL
-export ESLINT_DISABLE
 export PROXY_URL
 export STOREFRONT_ASSETS_PORT
 export STOREFRONT_PROXY_PORT
+export STOREFRONT_HTTPS_KEY_FILE
+export STOREFRONT_HTTPS_CERTIFICATE_FILE
+export STOREFRONT_SKIP_SSL_CERT
 
 if [[ -e "${PROJECT_ROOT}/vendor/shopware/platform" ]]; then
     STOREFRONT_ROOT="${STOREFRONT_ROOT:-"${PROJECT_ROOT}/vendor/shopware/platform/src/Storefront"}"
@@ -65,7 +67,7 @@ if [[ $(command -v jq) ]]; then
         if [[ -f "$path/package.json" && ! -d "$path/node_modules" && $name != "storefront" ]]; then
             echo "=> Installing npm dependencies for ${name}"
 
-            npm install --prefix "$path"
+            (cd "$path" && npm install)
         fi
     done
     cd "$OLDPWD" || exit
diff --git a/shopware/platform/6.6/manifest.json b/shopware/platform/6.7/manifest.json
index f355e10..8e171c3 100644
--- a/shopware/platform/6.6/manifest.json
+++ b/shopware/platform/6.7/manifest.json
@@ -31,6 +31,9 @@
         "Shopware\\Core\\Profiling\\Profiling": [
             "all"
         ],
+        "Shopware\\Core\\Service\\Service": [
+            "all"
+        ],
         "Shopware\\Administration\\Administration": [
             "all"
         ],
@@ -54,8 +57,6 @@
         "INSTANCE_ID": "%generate(secret)%",
         "BLUE_GREEN_DEPLOYMENT": "0",
         "DATABASE_URL": "mysql:\/\/root:root@localhost\/shopware",
-        "#1": "With Shopware 6.4.17.0 the MAILER_DSN variable will be used in this template instead of MAILER_URL",
-        "MAILER_URL": "null:\/\/null",
         "PROXY_URL": "http:\/\/localhost",
         "SHOPWARE_HTTP_CACHE_ENABLED": "1",
         "SHOPWARE_HTTP_DEFAULT_TTL": "7200",
diff --git a/shopware/platform/6.6/public/.htaccess.dist b/shopware/platform/6.7/public/.htaccess.dist
index bf32313..3e64081 100644
--- a/shopware/platform/6.6/public/.htaccess.dist
+++ b/shopware/platform/6.7/public/.htaccess.dist
@@ -30,6 +30,7 @@ DirectoryIndex index.php
     RewriteRule ^ - [L]
 
     # Rewrite all other queries to the front controller.
+    RewriteCond %{REQUEST_URI} !^/(theme|media|thumbnail|bundles|css|fonts|js|recovery)/ [NC]
     RewriteRule ^ %{ENV:BASE}/index.php [L]
 </IfModule>
 
diff --git a/shopware/platform/6.6/public/index.php b/shopware/platform/6.7/public/index.php
index fe36139..1fc45df 100644
--- a/shopware/platform/6.6/public/index.php
+++ b/shopware/platform/6.7/public/index.php
@@ -2,6 +2,7 @@
 
 use Shopware\Core\DevOps\Environment\EnvironmentHelper;
 use Shopware\Core\Framework\Plugin\KernelPluginLoader\ComposerPluginLoader;
+use Shopware\Core\Installer\Helper\InstallerRedirectHelper;
 use Shopware\Core\Installer\InstallerKernel;
 use Shopware\Core\Framework\Adapter\Kernel\KernelFactory;
 
@@ -21,7 +22,14 @@ return function (array $context) {
         $baseURL = rtrim($baseURL, '/');
 
         if (strpos($_SERVER['REQUEST_URI'], '/installer') === false) {
-            header('Location: ' . $baseURL . '/installer');
+            // InstallerRedirectHelper was introduced in 6.7.5.0; older 6.7 patch releases
+            // ship no such class, so forward the sanitised query only when it is available.
+            $query = match (true) {
+                class_exists(InstallerRedirectHelper::class) => (new InstallerRedirectHelper($_SERVER))->buildQueryString(),
+                default => '',
+            };
+
+            header('Location: ' . $baseURL . '/installer' . $query);
             exit;
         }
     }
diff --git a/shopware/platform/6.6/root/.htaccess b/shopware/platform/6.7/root/.htaccess
index 6c961e7..8d2e431 100644
--- a/shopware/platform/6.6/root/.htaccess
+++ b/shopware/platform/6.7/root/.htaccess
@@ -1,3 +1,5 @@
+# This file will be overwritten on any Shopware Update. For adjustments edit the .htaccess file inside the public folder
+
 DirectoryIndex index.html index.php
 
 <IfModule mod_negotiation.c>

@keulinho Jonas Elfering (keulinho) changed the title fix(media): align Apache static-asset CSP across recipes fix(media): protect static assets in Apache and Fastly recipes Oct 15, 2026
@keulinho Jonas Elfering (keulinho) changed the title fix(media): protect static assets in Apache and Fastly recipes fix(media): align Apache static-asset CSP across recipes Oct 15, 2026
@keulinho
Jonas Elfering (keulinho) marked this pull request as ready for review October 15, 2026 11:32
@keulinho
Jonas Elfering (keulinho) merged commit 5e94681 into main Oct 16, 2026
3 checks passed
@keulinho
Jonas Elfering (keulinho) deleted the codex/static-html-svg-csp branch October 16, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants