From db755b63957416c28b1382b0c523f44a72deb21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Franco?= Date: Thu, 3 Sep 2026 20:58:40 +0200 Subject: [PATCH 1/5] fix(demo): mark path repo as Git safe.directory for CI smoke Composer path repositories mount the bundle at /var/auth-kit-bundle with host-owned files; without safe.directory Composer cannot symlink the local package and the demo returns HTTP 500 in demo-smoke. --- demo/symfony8/Dockerfile | 3 ++- demo/symfony8/docker/entrypoint.sh | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/demo/symfony8/Dockerfile b/demo/symfony8/Dockerfile index 7cb1f30..493151a 100644 --- a/demo/symfony8/Dockerfile +++ b/demo/symfony8/Dockerfile @@ -7,7 +7,8 @@ RUN install-php-extensions intl pdo_mysql zip COPY --from=composer:2 /usr/bin/composer /usr/bin/composer -RUN git config --global --add safe.directory /app +RUN git config --global --add safe.directory /app && \ + git config --global --add safe.directory /var/auth-kit-bundle WORKDIR /app diff --git a/demo/symfony8/docker/entrypoint.sh b/demo/symfony8/docker/entrypoint.sh index e5c30df..22b0591 100644 --- a/demo/symfony8/docker/entrypoint.sh +++ b/demo/symfony8/docker/entrypoint.sh @@ -1,6 +1,9 @@ #!/bin/sh set -e +git config --global --add safe.directory /app 2>/dev/null || true +git config --global --add safe.directory /var/auth-kit-bundle 2>/dev/null || true + # Wait until Composer has installed the app (make up runs install after start). # Without this, FrankenPHP worker mode exits immediately on a clean checkout (CI). i=0 From 709d4ffe2cfe26af0bbb45650aeb83d6b556dfc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Franco?= Date: Thu, 3 Sep 2026 21:02:29 +0200 Subject: [PATCH 2/5] fix(demo): retry HTTP smoke after FrankenPHP worker reboot FrankenPHP reboots workers after cache:clear during make up; the single-shot curl in demo-smoke often runs before workers are ready and returns HTTP 500. Retry for up to 60s like other bundle demos. --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 66e7dc4..c9f1a99 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,15 @@ demo-smoke: [ -z "$$PORT" ] && PORT=$$(grep "^PORT=" demo/symfony8/.env.example 2>/dev/null | cut -d= -f2 | tr -d '\r'); \ [ -z "$$PORT" ] && PORT=8010; \ echo "Smoke GET http://localhost:$$PORT/en/login"; \ - code=$$(curl -fsS -o /dev/null -w "%{http_code}" "http://localhost:$$PORT/en/login" || true); \ + code=000; \ + i=0; \ + while [ $$i -lt 30 ]; do \ + code=$$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$$PORT/en/login" || true); \ + [ -z "$$code" ] && code=000; \ + if [ "$$code" = "200" ]; then break; fi; \ + i=$$((i+1)); \ + sleep 2; \ + done; \ if [ "$$code" != "200" ]; then echo "demo-smoke failed: HTTP $$code"; exit 1; fi; \ echo "demo-smoke OK (HTTP 200)" From cc71e721f168e732aab91076820899fbd8a89ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Franco?= Date: Thu, 3 Sep 2026 21:07:55 +0200 Subject: [PATCH 3/5] fix(twig): stub SlideToConfirm Twig functions when package absent Twig compiles calls in _slide_to_confirm_assets.html.twig even inside {% if %}, so demo-smoke HTTP 500 when slide-to-confirm is not installed. Register no-op stubs until the optional bundle provides real functions. --- src/Twig/AuthKitUiExtension.php | 11 ++++++++++- tests/Unit/Twig/AuthKitUiExtensionTest.php | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Twig/AuthKitUiExtension.php b/src/Twig/AuthKitUiExtension.php index 99e7efb..cec85bf 100644 --- a/src/Twig/AuthKitUiExtension.php +++ b/src/Twig/AuthKitUiExtension.php @@ -55,12 +55,21 @@ public function getGlobals(): array public function getFunctions(): array { - return [ + $functions = [ new TwigFunction('nowo_auth_kit_outbound_mail_ready', $this->isOutboundMailReady(...)), new TwigFunction('nowo_auth_kit_slide_to_confirm_assets', $this->shouldLoadSlideToConfirmAssets(...)), new TwigFunction('nowo_auth_kit_device_intelligence_assets', $this->shouldLoadDeviceIntelligenceAssets(...)), new TwigFunction('nowo_auth_kit_otp_input_assets', $this->shouldLoadOtpInputAssets(...)), ]; + + // Optional bundle Twig functions are referenced in _slide_to_confirm_assets.html.twig; + // register no-op stubs so templates compile when the package is not installed. + if (!class_exists('Nowo\\SlideToConfirmBundle\\Twig\\NowoSlideToConfirmTwigExtension')) { + $functions[] = new TwigFunction('nowo_slide_to_confirm_asset_path', static fn (): string => ''); + $functions[] = new TwigFunction('nowo_slide_to_confirm_asset_package', static fn (): string => ''); + } + + return $functions; } public function isOutboundMailReady(): bool diff --git a/tests/Unit/Twig/AuthKitUiExtensionTest.php b/tests/Unit/Twig/AuthKitUiExtensionTest.php index 1b3c6e4..902ba4b 100644 --- a/tests/Unit/Twig/AuthKitUiExtensionTest.php +++ b/tests/Unit/Twig/AuthKitUiExtensionTest.php @@ -67,7 +67,7 @@ public function testRegistersOutboundMailReadyTwigFunction(): void $extension = new AuthKitUiExtension([], [], new AlwaysOutboundMailReadyChecker()); $functions = $extension->getFunctions(); - self::assertCount(4, $functions); + self::assertCount(class_exists('Nowo\\SlideToConfirmBundle\\Twig\\NowoSlideToConfirmTwigExtension') ? 4 : 6, $functions); self::assertSame('nowo_auth_kit_outbound_mail_ready', $functions[0]->getName()); self::assertSame('nowo_auth_kit_slide_to_confirm_assets', $functions[1]->getName()); self::assertSame('nowo_auth_kit_device_intelligence_assets', $functions[2]->getName()); From f999a2ea07501f07c9b4f131872470f4ad156644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Franco?= Date: Thu, 3 Sep 2026 21:10:22 +0200 Subject: [PATCH 4/5] test(twig): cover SlideToConfirm stub Twig functions --- tests/Unit/Twig/AuthKitUiExtensionTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Unit/Twig/AuthKitUiExtensionTest.php b/tests/Unit/Twig/AuthKitUiExtensionTest.php index 902ba4b..d7b7ba9 100644 --- a/tests/Unit/Twig/AuthKitUiExtensionTest.php +++ b/tests/Unit/Twig/AuthKitUiExtensionTest.php @@ -62,6 +62,22 @@ public function isReady(): bool self::assertFalse($extension->isOutboundMailReady()); } + public function testRegistersSlideToConfirmStubTwigFunctionsWhenBundleAbsent(): void + { + if (class_exists('Nowo\\SlideToConfirmBundle\\Twig\\NowoSlideToConfirmTwigExtension')) { + self::markTestSkipped('SlideToConfirm bundle is installed in this environment.'); + } + + $extension = new AuthKitUiExtension([], [], new AlwaysOutboundMailReadyChecker()); + $byName = []; + foreach ($extension->getFunctions() as $function) { + $byName[$function->getName()] = $function->getCallable(); + } + + self::assertSame('', $byName['nowo_slide_to_confirm_asset_path']()); + self::assertSame('', $byName['nowo_slide_to_confirm_asset_package']()); + } + public function testRegistersOutboundMailReadyTwigFunction(): void { $extension = new AuthKitUiExtension([], [], new AlwaysOutboundMailReadyChecker()); From 4ca602b28159ee4986d531ee1a81e0c7ce3469e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Franco?= Date: Thu, 3 Sep 2026 21:14:39 +0200 Subject: [PATCH 5/5] fix(twig): satisfy PHPStan and 100% coverage for slide stubs Ignore optional stub closure lines when slide-to-confirm is present in dev dependencies; keep a regression test for demo installs without it. --- src/Twig/AuthKitUiExtension.php | 4 ++-- tests/Unit/Twig/AuthKitUiExtensionTest.php | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Twig/AuthKitUiExtension.php b/src/Twig/AuthKitUiExtension.php index cec85bf..b85b804 100644 --- a/src/Twig/AuthKitUiExtension.php +++ b/src/Twig/AuthKitUiExtension.php @@ -65,8 +65,8 @@ public function getFunctions(): array // Optional bundle Twig functions are referenced in _slide_to_confirm_assets.html.twig; // register no-op stubs so templates compile when the package is not installed. if (!class_exists('Nowo\\SlideToConfirmBundle\\Twig\\NowoSlideToConfirmTwigExtension')) { - $functions[] = new TwigFunction('nowo_slide_to_confirm_asset_path', static fn (): string => ''); - $functions[] = new TwigFunction('nowo_slide_to_confirm_asset_package', static fn (): string => ''); + $functions[] = new TwigFunction('nowo_slide_to_confirm_asset_path', static fn (): string => ''); // @codeCoverageIgnore + $functions[] = new TwigFunction('nowo_slide_to_confirm_asset_package', static fn (): string => ''); // @codeCoverageIgnore } return $functions; diff --git a/tests/Unit/Twig/AuthKitUiExtensionTest.php b/tests/Unit/Twig/AuthKitUiExtensionTest.php index d7b7ba9..9cc9f5e 100644 --- a/tests/Unit/Twig/AuthKitUiExtensionTest.php +++ b/tests/Unit/Twig/AuthKitUiExtensionTest.php @@ -74,8 +74,15 @@ public function testRegistersSlideToConfirmStubTwigFunctionsWhenBundleAbsent(): $byName[$function->getName()] = $function->getCallable(); } - self::assertSame('', $byName['nowo_slide_to_confirm_asset_path']()); - self::assertSame('', $byName['nowo_slide_to_confirm_asset_package']()); + self::assertArrayHasKey('nowo_slide_to_confirm_asset_path', $byName); + self::assertArrayHasKey('nowo_slide_to_confirm_asset_package', $byName); + + /** @var callable(): string $pathCallable */ + $pathCallable = $byName['nowo_slide_to_confirm_asset_path']; + /** @var callable(): string $packageCallable */ + $packageCallable = $byName['nowo_slide_to_confirm_asset_package']; + self::assertSame('', $pathCallable()); + self::assertSame('', $packageCallable()); } public function testRegistersOutboundMailReadyTwigFunction(): void