From 0ec4e02ec60e918701863fc5962cfcf5acae6ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brian=20Sch=C3=A4ffner?= Date: Fri, 9 Oct 2026 13:34:17 +0200 Subject: [PATCH 1/2] fix: require safe Symfony components and preserve reused environment values --- CHANGELOG.md | 6 +++ README.md | 2 +- composer.json | 6 +-- docs/README.md | 2 +- docs/dependency-injection.md | 4 +- tests/Kernel/DiscardedEnvExtension.php | 31 +++++++++++++ .../EnvPlaceholderCompatibilityTest.php | 46 +++++++++++++++++++ 7 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 tests/Kernel/DiscardedEnvExtension.php create mode 100644 tests/Kernel/EnvPlaceholderCompatibilityTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d7ca0b..6b48b3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) where applicable. +## 1.1.8 — 2026-10-09 + +- Require maintained Symfony Routing and YAML 8.1 or newer, excluding the vulnerable 8.0 releases covered by the May 2026 advisories. +- Require Symfony DependencyInjection 8.1.8 or newer so environment placeholders reused after an earlier extension discards them remain resolvable in compiled containers. +- Verify environment resolution through container creation and cached-container reload with two extensions sharing an overridden environment value. + ## 1.1.7 — 2026-10-06 - Isolate native compiler-pass state when rebuilding a runtime container after diff --git a/README.md b/README.md index 4cc2e41..978e782 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Then it adds the Symfony patterns that pay off in larger codebases: - PHP `^8.5` - Composer - WordPress -- Symfony DependencyInjection `^8.1`, Config, Console, Filesystem, Routing, +- Symfony DependencyInjection `^8.1.8`, Config, Console, Filesystem, Routing, Service Contracts, EventDispatcher, Clock, ExpressionLanguage, and Yaml components diff --git a/composer.json b/composer.json index 2b2fc9d..3a75406 100644 --- a/composer.json +++ b/composer.json @@ -20,15 +20,15 @@ "symfony/config": "^8.0", "symfony/console": "^8.0", "symfony/clock": "^8.0", - "symfony/dependency-injection": "^8.1", + "symfony/dependency-injection": "^8.1.8", "symfony/event-dispatcher": "^8.0", "symfony/expression-language": "^8.0", "symfony/filesystem": "^8.0", "symfony/http-foundation": "^8.1", "symfony/http-kernel": "^8.1", - "symfony/routing": "^8.0", + "symfony/routing": "^8.1", "symfony/service-contracts": "^3.6", - "symfony/yaml": "^8.0" + "symfony/yaml": "^8.1" }, "require-dev": { "sympress/qa": "^0.1.2" diff --git a/docs/README.md b/docs/README.md index f7e3797..58996c5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,7 +5,7 @@ It boots exactly one global site-level container, discovers active MU plugins, plugins, and themes as bundles, and imports their `Resources/config/` directories into that same container. -The current kernel targets Symfony DependencyInjection `^8.1`. It keeps the +The current kernel targets Symfony DependencyInjection `^8.1.8`. It keeps the WordPress-specific pieces small: package discovery, runtime hydration, hook registration, and WP-CLI bridging. Bundle lifecycle, configurable extensions, service locators, tagged iterators, resettable services, and most attributes use diff --git a/docs/dependency-injection.md b/docs/dependency-injection.md index c45857f..19cef1b 100644 --- a/docs/dependency-injection.md +++ b/docs/dependency-injection.md @@ -16,12 +16,12 @@ build, configure, dump, and run the container: "symfony/config": "^8.0", "symfony/console": "^8.0", "symfony/clock": "^8.0", - "symfony/dependency-injection": "^8.1", + "symfony/dependency-injection": "^8.1.8", "symfony/event-dispatcher": "^8.0", "symfony/expression-language": "^8.0", "symfony/filesystem": "^8.0", "symfony/service-contracts": "^3.6", - "symfony/yaml": "^8.0" + "symfony/yaml": "^8.1" } } ``` diff --git a/tests/Kernel/DiscardedEnvExtension.php b/tests/Kernel/DiscardedEnvExtension.php new file mode 100644 index 0000000..f4dab0c --- /dev/null +++ b/tests/Kernel/DiscardedEnvExtension.php @@ -0,0 +1,31 @@ +getRootNode()->children()->scalarNode('value')->end()->end(); + return $tree; + } + }; + $this->processConfiguration($configuration, $configs); + } +} diff --git a/tests/Kernel/EnvPlaceholderCompatibilityTest.php b/tests/Kernel/EnvPlaceholderCompatibilityTest.php new file mode 100644 index 0000000..0867b0d --- /dev/null +++ b/tests/Kernel/EnvPlaceholderCompatibilityTest.php @@ -0,0 +1,46 @@ +tmpPath('reused-extension-env'); + $bundleDir = $this->tmpPath('reused-extension-bundle'); + mkdir($bundleDir, 0700, true); + file_put_contents($bundleDir . '/composer.json', '{}'); + $registry = $this->registry($bundleDir); + $kernel = $this->kernel($projectDir); + $container = $kernel->createContainer(); + $container->builder()->registerExtension(new DiscardedEnvExtension()); + $container->builder()->registerExtension(new class extends Extension { + public function getAlias(): string + { + return 'reused'; + } + + public function load(array $configs, ContainerBuilder $container): void + { + $container->setParameter('reused.value', $configs[0]['value']); + } + }); + $container->builder()->prependExtensionConfig('discarded', ['value' => 'overridden']); + $container->builder()->prependExtensionConfig('discarded', ['value' => '%env(APP_RUNTIME_MODE)%']); + $container->builder()->prependExtensionConfig('reused', ['value' => '%env(APP_RUNTIME_MODE)%']); + $_ENV['APP_RUNTIME_MODE'] = 'fixture-value'; + + $kernel->createRuntimeContainer($container, $registry, []); + self::assertSame('fixture-value', $container->getParameter('reused.value')); + + $cachedKernel = $this->kernel($projectDir); + $cached = $cachedKernel->createContainer(); + self::assertTrue($cachedKernel->tryUseRuntimeContainer($cached, $registry)); + self::assertSame('fixture-value', $cached->getParameter('reused.value')); + } +} From c31829d630ad13cbd7592e850289fb1b3f923669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brian=20Sch=C3=A4ffner?= Date: Fri, 9 Oct 2026 13:50:23 +0200 Subject: [PATCH 2/2] docs: verify native compile-time environment diagnostics --- CHANGELOG.md | 1 + docs/README.md | 2 + docs/compile-time-environment.md | 41 ++++++++++++++++++++ tools/check-compile-time-env.php | 64 ++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 docs/compile-time-environment.md create mode 100644 tools/check-compile-time-env.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b48b3c..7e85d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ where applicable. - Require maintained Symfony Routing and YAML 8.1 or newer, excluding the vulnerable 8.0 releases covered by the May 2026 advisories. - Require Symfony DependencyInjection 8.1.8 or newer so environment placeholders reused after an earlier extension discards them remain resolvable in compiled containers. - Verify environment resolution through container creation and cached-container reload with two extensions sharing an overridden environment value. +- Document the native Symfony 8.2 compile-time environment log and add a synthetic availability probe that outputs names and configuration paths only. Stable dependencies remain unchanged; the feature requires the future upstream API. ## 1.1.7 — 2026-10-06 diff --git a/docs/README.md b/docs/README.md index 58996c5..2452a72 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,6 +13,8 @@ the original Symfony component behavior. ## Contents +- [Native compile-time environment diagnostics](compile-time-environment.md) + - `boot-and-bundles.md` - `services-and-autowiring.md` - `dependency-injection.md` diff --git a/docs/compile-time-environment.md b/docs/compile-time-environment.md new file mode 100644 index 0000000..e362e55 --- /dev/null +++ b/docs/compile-time-environment.md @@ -0,0 +1,41 @@ +# Native compile-time environment diagnostics + +Symfony 8.2's `resolvesAtCompileTime()` configuration node API and native +`MergeExtensionConfigurationPass` log explain which environment variables were +inlined and which option or extension requested them. These APIs are not yet +stable as of 2026-10-09. Kernel continues to require stable DI `^8.1.8` and does +not introduce a development dependency or copy the upstream implementation. + +The existing Kernel `debug:container --env-vars` command lists remaining +`%env(...)%` references. It does not identify values consumed at compile time. +With Framework Bundle, the framework command of the same name uses Symfony's +native descriptors. They are distinct implementations; no second descriptor or +compile-time resolver is introduced here. + +For a configured `ContainerBuilder` in an explicit development build, read +`$builder->getCompiler()->getLog()` after compilation. Select only the native +`Inlined env var` records and output their variable name and option/extension +identifier. Do not print the entire compiler log or resolved parameter values: +other compiler passes can log arbitrary application data. + +```php +foreach ($builder->getCompiler()->getLog() as $line) { + if (preg_match('/Inlined env var "%env\(([A-Za-z0-9_:]+)\)%" (into option|while loading extension) "([A-Za-z0-9_.-]+)"\./', $line, $matches) === 1) { + printf("%s\t%s=%s\n", $matches[1], $matches[2], $matches[3]); + } +} +``` + +`php tools/check-compile-time-env.php` runs a synthetic native configuration probe +and prints only the variable and configuration path. On stable 8.1 it exits with +code 2 and an explicit unavailable-API message. The probe has been verified with +the upstream 8.2 Config/DI source; it does not certify a stable 8.2 release. + +Kernel currently does not mark its own configuration nodes with +`resolvesAtCompileTime()`. These records therefore become relevant when a +consumer's extension opts into the new native API. Existing cached PHP containers +do not retain a complete compiler log; inspect an explicit fresh build, rather +than rebuilding during normal requests just to collect diagnostics. + +Sources: [API rename](https://github.com/symfony/symfony/pull/66642), +[native compiler log](https://github.com/symfony/symfony/pull/66717). diff --git a/tools/check-compile-time-env.php b/tools/check-compile-time-env.php new file mode 100644 index 0000000..505679d --- /dev/null +++ b/tools/check-compile-time-env.php @@ -0,0 +1,64 @@ +registerExtension(new class extends Extension { + public function getAlias(): string + { + return 'fixture'; + } + + public function load(array $configs, ContainerBuilder $container): void + { + $configuration = new class implements ConfigurationInterface { + public function getConfigTreeBuilder(): TreeBuilder + { + $tree = new TreeBuilder('fixture'); + $node = $tree->getRootNode()->children()->booleanNode('enabled'); + $node->resolvesAtCompileTime(); + return $tree; + } + }; + $config = $this->processConfiguration($configuration, $configs); + $container->setParameter('fixture.enabled', $config['enabled']); + } +}); +$container->loadFromExtension('fixture', ['enabled' => '%env(bool:SYMPRESS_TEST_FEATURE)%']); +$previous = $_ENV['SYMPRESS_TEST_FEATURE'] ?? null; +$_ENV['SYMPRESS_TEST_FEATURE'] = '1'; +try { + (new MergeExtensionConfigurationPass())->process($container); + if ($container->getParameter('fixture.enabled') !== true) { + throw new RuntimeException('Native compile-time resolution was not applied.'); + } + foreach ($container->getCompiler()->getLog() as $line) { + if (preg_match('/Inlined env var "%env\(([A-Za-z0-9_:]+)\)%" into option "([A-Za-z0-9_.-]+)"\./', $line, $matches) === 1) { + if ($matches[1] === 'bool:SYMPRESS_TEST_FEATURE' && $matches[2] === 'fixture.enabled') { + echo $matches[1] . "\toption=" . $matches[2] . "\n"; + exit(0); + } + } + } + throw new RuntimeException('The native compiler log did not identify the inlined variable and configuration path.'); +} finally { + if ($previous === null) { + unset($_ENV['SYMPRESS_TEST_FEATURE']); + } else { + $_ENV['SYMPRESS_TEST_FEATURE'] = $previous; + } +}