diff --git a/CHANGELOG.md b/CHANGELOG.md index f798625..87dc08e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ 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.0.8 — 2026-10-23 + +- Rebuild container diagnostics on a cloned kernel so lint/debug commands preserve active containers, booted bundles and final shutdown cleanup. +- Add a regression that verifies live container and bundle identity and successful shutdown after diagnostics. + ## 1.0.7 — 2026-10-16 - Require Symfony ExpressionLanguage 8.1.9 and YAML 8.1.6 or newer to exclude CVE-2026-109449 and CVE-2026-109413. diff --git a/src/Console/Command/DebugContainerBuilderTrait.php b/src/Console/Command/DebugContainerBuilderTrait.php index 0cefb62..afee883 100644 --- a/src/Console/Command/DebugContainerBuilderTrait.php +++ b/src/Console/Command/DebugContainerBuilderTrait.php @@ -19,6 +19,7 @@ protected function debugContainerBuilder(Container $container): ContainerBuilder // Serialized debug snapshots have already undergone optimization. // Re-running extension/compiler passes on them can dereference // services removed by the original compilation (e.g. Twig's iterator). + $kernel = clone $kernel; $fresh = $kernel->createContainer(); $kernel->configureContainer($fresh->builder(), $fresh, $kernel->discoverBundles()); $fresh->builder()->getCompilerPassConfig()->setMergePass( diff --git a/tests/Cache/DebugContainerBuilderTest.php b/tests/Cache/DebugContainerBuilderTest.php index b951d3c..6f20bb6 100644 --- a/tests/Cache/DebugContainerBuilderTest.php +++ b/tests/Cache/DebugContainerBuilderTest.php @@ -8,6 +8,10 @@ use PHPUnit\Framework\Attributes\DataProvider; use SymPress\Framework\Console\Command\DebugContainerBuilderTrait; use SymPress\Kernel\Bundle\BundleRegistry; +use SymPress\Kernel\Bundle\AbstractBundle; +use SymPress\Kernel\Bundle\BundleMetadata; +use SymPress\Kernel\Kernel\AbstractKernel; +use Symfony\Component\Filesystem\Filesystem; use SymPress\Kernel\Container; use SymPress\Kernel\Kernel\KernelInterface; use Symfony\Component\DependencyInjection\Container as CompiledContainer; @@ -78,6 +82,56 @@ public function inspect(Container $container): ContainerBuilder } } + public function testDiagnosticsPreserveBootedKernelContainerAndBundleShutdown(): void + { + $root = sys_get_temp_dir() . '/diagnostic-lifecycle-' . bin2hex(random_bytes(8)); + mkdir($root, 0700, true); + file_put_contents($root . '/composer.json', '{}'); + $kernel = new class ($root, 'test', false) extends AbstractKernel { + public function discoverBundles(): BundleRegistry + { + return new BundleRegistry(); + } + }; + $bundle = new class extends AbstractBundle { + public int $shutdowns = 0; + public function shutdown(): void + { + ++$this->shutdowns; + } + }; + $registry = (new BundleRegistry())->add(new BundleMetadata( + 'fixture/lifecycle', 'library', 'fixture', $root, $root . '/composer.json', $bundle, + )); + $container = $kernel->createContainer(); + try { + $files = $kernel->configureContainer($container->builder(), $container, $registry); + $kernel->createRuntimeContainer($container, $registry, $files); + $kernel->boot($container, $registry); + $liveBundles = $kernel->getBundles(); + $runtime = $container->runtimeContainer(); + $probe = new class { + use DebugContainerBuilderTrait; + public function inspect(Container $container): ContainerBuilder + { + return $this->debugContainerBuilder($container); + } + }; + + $builder = $probe->inspect($container); + $builder->compile(); + + self::assertSame($container, $kernel->getContainer()); + self::assertSame($runtime, $container->runtimeContainer()); + self::assertSame($liveBundles, $kernel->getBundles()); + $kernel->shutdown(); + self::assertSame(1, $bundle->shutdowns); + } finally { + $kernel->shutdown(); + (new Filesystem())->remove($root); + } + } + /** @return iterable */ public static function snapshots(): iterable {